
Statute Analysis
- 45 installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
Statute Analysis is a Claude skill that interprets statutes and regulations and maps them into classified compliance requirements using legal hierarchy, canons of construction and operative-keyword analysis.
About
Statute Analysis is a framework for reading, interpreting and applying statutes, regulations and rules. It walks the legal hierarchy, applies canons of construction, extracts operative keywords (shall/must/may), and classifies requirements into obligations, permissions, conditions and exemptions. Two Python tools scan statute text for operative keywords and classify requirements by type, implementation team, enforcement mechanism and penalty. It is used to map compliance obligations from legislative text and is explicitly marked experimental and not legal advice.
- Interprets statutes and regulations: legal hierarchy, canons of construction, operative keywords
- Classifies requirements by type, implementation team, enforcement and penalty
- Maps compliance obligations from legislative text (marked experimental, not legal advice)
Statute Analysis by the numbers
- 45 all-time installs (skills.sh)
- Ranked #1,373 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
statute-analysis capabilities & compatibility
Free; runs local Python scripts on statute text, no API keys.
- Use cases
- security audit · research
- Pricing
- Free
What statute-analysis says it does
Statute and regulation interpretation framework. Use when reading statutes, classifying requirements, analyzing operative keywords, applying canons of construction, or mapping compliance obligatio
This skill is provided for educational and informational purposes only. It does NOT constitute legal advice.
Classifies statutory requirements by type, implementation team, enforcement mechanism, and penalty.
npx skills add https://github.com/borghei/claude-skills --skill statute-analysisAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 45 |
|---|---|
| repo stars | ★ 451 |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
What it does
Interpret statutes and map compliance obligations from legislative text into classified requirements.
Who is it for?
Reading statutes, classifying requirements, and mapping compliance obligations from legislative text.
Skip if: Producing legal advice; it is explicitly experimental and informational only.
When should I use this skill?
You are reading a statute, classifying requirements, analyzing operative keywords, or mapping compliance obligations from legislative text.
What you get
Classified statutory requirements (obligations, permissions, conditions, exemptions) with implementation team, enforcement mechanism and penalty mapped.
- Operative-keyword analysis
- Classified requirements
- Implementation obligation matrix
By the numbers
- 2 Python tools (statute keyword analyzer, requirement classifier)
- 6-level legal hierarchy (Constitution to case law)
Files
⚠️ EXPERIMENTAL — This skill is provided for educational and informational purposes only. It does NOT constitute legal advice. All responsibility for usage rests with the user. Consult qualified legal professionals before acting on any output.
Statute Analysis
Production-ready framework for reading, interpreting, and applying statutes, regulations, and rules. Covers the full lifecycle from identifying the legal hierarchy through extracting actionable requirements and mapping implementation obligations.
---
Table of Contents
- Legal Hierarchy
- Preliminary Steps
- Tools
- Core Interpretation Techniques
- Canons of Construction
- Interpretation Sources
- Requirement Classification
- Cross-Jurisdictional Analysis
- Reference Guides
- Workflows
- Troubleshooting
- Success Criteria
- Scope and Limitations
- Anti-Patterns
- Tool Reference
---
Legal Hierarchy
Understanding the source hierarchy is the foundation of statutory analysis.
| Source | Created By | Authority | Example |
|---|---|---|---|
| Constitution | Sovereign/people | Supreme | U.S. Constitution, EU Treaties |
| Statute | Legislature | Primary legislation | GDPR, Clean Air Act, AI Act |
| Regulation | Executive agency | Delegated authority | FDA 21 CFR, FTC rules |
| Rule | Agency or court | Procedural/interpretive | Federal Rules of Civil Procedure |
| Guidance | Agency | Non-binding, persuasive | FDA guidance documents, CNIL guides |
| Case law | Courts | Binding within jurisdiction | Supreme Court precedent |
Key principle: Higher sources override lower sources. Regulations cannot exceed statutory authority. Guidance cannot create new obligations not grounded in statute.
---
Preliminary Steps
Before interpreting any statutory provision, complete these checks:
1. Verify currency and status -- Is this the current, in-force version? Check for amendments, repeals, or sunset clauses. Use official sources (government gazettes, EUR-Lex, congress.gov). 2. Understand the regulatory ecosystem -- What regulations, rules, and guidance implement this statute? Map the full hierarchy. 3. Browse the full structure -- Read the table of contents, definitions section, scope provisions, and transitional articles before diving into specific sections. 4. Identify the definitions section -- Almost all statutes define key terms. These definitions override ordinary meaning. 5. Check effective dates -- Different provisions may have different effective dates. Map the compliance timeline. 6. Identify your role -- Statutes impose different obligations depending on the reader's role (e.g., "provider" vs "deployer" in the EU AI Act, "controller" vs "processor" in GDPR).
---
Tools
Statute Keyword Analyzer
Scans statute text for operative keywords and classifies obligations, permissions, conditions, and exemptions.
# Analyze a statute file
python scripts/statute_keyword_analyzer.py --input statute.txt
# Analyze with JSON output
python scripts/statute_keyword_analyzer.py --input regulation.txt --json
# Analyze inline text
python scripts/statute_keyword_analyzer.py --text "The controller shall implement appropriate technical measures..."
# Save analysis report
python scripts/statute_keyword_analyzer.py --input statute.txt --output analysis.jsonRequirement Classifier
Classifies statutory requirements by type, implementation team, enforcement mechanism, and penalty.
# Classify requirements from a JSON list
python scripts/requirement_classifier.py --input requirements.json
# Classify with JSON output
python scripts/requirement_classifier.py --input requirements.json --json
# Classify inline requirement
python scripts/requirement_classifier.py --text "Controllers must provide data subjects with a privacy notice at the point of collection"
# Generate implementation matrix
python scripts/requirement_classifier.py --input requirements.json --output matrix.json---
Core Interpretation Techniques
Definitions Analysis
Statutory definitions control meaning. Pay attention to the verb used:
| Verb | Type | Meaning | Example |
|---|---|---|---|
| "means" | Exhaustive | The definition is complete; no other meaning applies | "'Personal data' means any information relating to an identified or identifiable natural person" |
| "includes" | Illustrative | The definition provides examples but is not limited to them | "'Processing' includes collection, recording, organization, structuring..." |
| "does not include" | Exclusion | Explicitly carves out items from scope | "'Consumer' does not include a natural person acting in a commercial or employment context" |
| "refers to" | Pointer | Incorporates an external definition | "'Harmonised standard' refers to a European standard as defined in Regulation (EU) No 1025/2012" |
Operative Keywords
| Keyword | Classification | Legal Effect |
|---|---|---|
| shall | Mandatory | Creates an obligation; must be done |
| must | Mandatory | Same as "shall" in modern drafting |
| may | Permissive | Creates permission; optional |
| may not | Prohibitive | Creates a prohibition |
| and | Conjunctive | All listed items required |
| or | Disjunctive | Any listed item sufficient |
| unless | Exception | Negates the rule when condition is met |
| except | Exception | Carves out specific items from the rule |
| subject to | Conditional | Rule applies but another provision modifies it |
| notwithstanding | Override | This provision prevails over conflicting provisions |
| provided that | Condition | Adds a requirement that must be satisfied |
| if...then | Conditional | Trigger condition and consequence |
| upon | Temporal trigger | Action required when event occurs |
Conjunctive vs Disjunctive Analysis
This distinction determines whether ALL conditions must be met or ANY single condition suffices.
| Pattern | Reading | Practical Impact |
|---|---|---|
| "A, B, and C" | All three required | Must satisfy every element |
| "A, B, or C" | Any one sufficient | Satisfy any single element |
| "A, B, and/or C" | Ambiguous | Flag for clarification; analyze context |
| "both A and B" | Explicitly conjunctive | Must satisfy both |
| "either A or B" | Explicitly disjunctive | Satisfy one |
| Serial comma ambiguity | Context-dependent | Apply whole-act rule for consistency |
---
Canons of Construction
See references/canons_of_construction.md for the complete 12-canon reference.
Quick Reference
| Canon | Core Rule | When to Apply |
|---|---|---|
| General-Terms Canon | General terms get general meaning | Default interpretation |
| Expressio Unius | Expressing one thing excludes others | Specific lists without catchall |
| Whole-Act Rule | Interpret provisions consistently | Apparent conflicts between sections |
| Consistent Usage | Same term = same meaning throughout | Term appears multiple times |
| Meaningful Variation | Different terms = different meanings | Similar but distinct terms used |
| Surplusage Canon | Every word has meaning; no redundancy | Tempted to treat words as surplus |
| Noscitur a Sociis | Words known by their associates | Ambiguous term in a list |
| Ejusdem Generis | General follows specific = limited | "...and other similar" patterns |
| Against Ineffectiveness | Prefer reading that gives effect | Two possible readings |
| Avoiding Absurdity | Reject absurd outcomes | Literal reading produces nonsensical result |
| Remedial Statutes | Construe liberally | Consumer protection, safety statutes |
| Rule of Lenity | Ambiguity favors the regulated party | Criminal or penalty provisions |
---
Interpretation Sources
When statutory text is ambiguous, consult sources in this order:
| Priority | Source | Weight | Where to Find |
|---|---|---|---|
| 1 | Statutory text itself | Controlling | Official gazette, codified law |
| 2 | Definitions section | Controlling | Usually first articles/sections |
| 3 | Legislative purpose (recitals, preamble) | Strong | Preamble, "Whereas" clauses |
| 4 | Canons of construction | Strong | Legal treatises, case law |
| 5 | Case law interpreting the provision | Strong-to-moderate | Court databases |
| 6 | Agency regulations implementing statute | Moderate | Agency websites, CFR |
| 7 | Agency guidance and FAQs | Persuasive only | Agency websites |
| 8 | Legislative history | Weak (varies by jurisdiction) | Congressional record, Hansard |
| 9 | Academic commentary | Persuasive only | Legal journals |
---
Requirement Classification
Every statutory requirement maps to an implementation category:
| Type | Description | Typical Owner | Example |
|---|---|---|---|
| Disclosure | Information must be provided to someone | Legal / Compliance | Privacy notice requirements |
| Operational | Process or procedure must exist | Operations / Compliance | Record-keeping obligations |
| Technical | System capability or safeguard required | Engineering | Encryption, access controls |
| UI/Design | User interface must include specific elements | Product / Design | Consent mechanisms, opt-out buttons |
| Organizational | Governance structure or role required | Management / HR | Appointing a DPO, board oversight |
| Documentation | Written records must be maintained | Legal / Compliance | Impact assessments, audit trails |
| Reporting | Information must be submitted to authority | Legal / Compliance | Breach notification, annual reports |
---
Cross-Jurisdictional Analysis
When requirements from multiple jurisdictions apply:
1. Map applicable jurisdictions -- Where are your users, your entity, and your data? 2. Identify overlapping requirements -- Many frameworks share common obligations. 3. Find the highest common denominator -- Design for the strictest requirement that satisfies all jurisdictions. 4. Flag conflicts -- Where requirements genuinely conflict, document the conflict and seek legal advice. 5. Check preemption -- Federal law may preempt state law; EU regulations may preempt member state law.
---
Enforcement Analysis
For each statutory requirement, assess enforcement risk:
| Factor | Assessment Questions |
|---|---|
| Enforcement authority | Which agency enforces? How active are they? |
| Penalty types | Civil fines, criminal penalties, administrative sanctions? |
| Penalty severity | Fixed amounts, percentage of turnover, per-violation? |
| Cure periods | Is there a right to cure before penalties apply? |
| Private right of action | Can individuals sue for violations? |
| Enforcement history | Has this provision been actively enforced? |
| Regulatory guidance | Has the agency clarified enforcement priorities? |
---
Reference Guides
| Guide | Path | Description |
|---|---|---|
| Canons of Construction | references/canons_of_construction.md | 12 canons with definitions, examples, and misapplication warnings |
| Statutory Structure | references/statutory_structure.md | How statutes are organized, effective dates, preemption, enforcement |
---
Workflows
Workflow 1: First Reading of a New Statute
1. Browse the full table of contents and structure. 2. Read the definitions section and scope provisions. 3. Check effective dates and transitional provisions. 4. Identify your role under the statute. 5. Run scripts/statute_keyword_analyzer.py on the full text. 6. Review the obligation/permission/exception map. 7. Identify provisions that apply to your role. 8. Validation: Definitions cataloged, role identified, key obligations listed.
Workflow 2: Requirement Extraction and Classification
1. Extract all provisions containing "shall," "must," or mandatory language. 2. For each requirement, identify: who (subject), what (action), when (trigger/deadline), how (standard). 3. Run scripts/requirement_classifier.py on the extracted requirements. 4. Review the implementation matrix. 5. Assign each requirement to an implementation team. 6. Prioritize by enforcement risk and deadline. 7. Validation: Every mandatory provision classified, assigned, and prioritized.
Workflow 3: Cross-Reference Resolution
1. Identify all cross-references in the target provision ("subject to Article X," "as defined in Section Y"). 2. Read each referenced provision in full. 3. Determine whether the cross-reference modifies, limits, or supplements the target provision. 4. Check for circular references or chains (A references B which references C). 5. Document the complete picture -- the target provision as modified by all cross-references. 6. Validation: All cross-references resolved; no orphan references.
---
Troubleshooting
| Problem | Likely Cause | Resolution |
|---|---|---|
| Term not defined in statute | Legislature used ordinary meaning | Apply general-terms canon; check case law for judicial definitions |
| "And/or" ambiguity | Drafting imprecision | Check legislative history; apply whole-act rule; flag for legal review |
| Conflicting provisions | Later provision may override earlier | Check for "notwithstanding" clauses; apply later-in-time rule |
| Undefined threshold | Delegated to regulation | Check implementing regulations and agency guidance |
| Provision seems to have no effect | May be transitional or placeholder | Check effective dates and amendment history |
| Cross-reference to repealed section | Statute not updated after amendment | Check saving clauses; apply presumption against ineffectiveness |
---
Success Criteria
| Criterion | Target |
|---|---|
| All defined terms cataloged | 100% of definitions section mapped |
| Obligations extracted | Every "shall/must" provision identified |
| Requirements classified | Each requirement has type, owner, enforcement, and priority |
| Cross-references resolved | No unresolved references remain |
| Enforcement risk assessed | Every material obligation has enforcement analysis |
| Implementation matrix complete | Requirements mapped to teams with timelines |
---
Scope & Limitations
In scope: Reading and interpreting statutory text, extracting requirements, classifying obligations, applying canons of construction, mapping enforcement risk.
Out of scope: Providing legal advice, predicting court outcomes, drafting legislation, interpreting case law holdings, constitutional analysis.
Disclaimer: This skill provides a structured methodology for statutory analysis. It does not constitute legal advice. Always consult qualified legal counsel for binding interpretations.
---
Anti-Patterns
| Anti-Pattern | Why It Fails | Better Approach |
|---|---|---|
| Reading a section in isolation | Statutes are interconnected; isolated reading misses cross-references, definitions, and scope limitations | Always read definitions, scope, and cross-referenced provisions before interpreting |
| Treating guidance as law | Agency guidance is non-binding and can change; building compliance solely on guidance creates risk | Use guidance to inform interpretation but anchor compliance to statutory text |
| Ignoring "what the statute doesn't say" | Silence can mean permission, delegation, or an oversight; assuming the statute covers everything leads to compliance gaps | Affirmatively check: does the statute address this scenario? If not, analyze why and what fills the gap |
| Applying one jurisdiction's interpretation to another | "Personal data" in GDPR is not identical to "personal information" in CCPA; cross-pollinating definitions creates errors | Analyze each statute independently using its own definitions and interpretive framework |
| Skipping the definitions section | Statutory definitions override ordinary meaning; missing them leads to fundamental misreadings | Always read the definitions section first, before any substantive analysis |
---
Tool Reference
| Tool | Input | Output | Use Case |
|---|---|---|---|
statute_keyword_analyzer.py | Statute text file or inline text | Obligation/permission/exception map | First pass analysis of any legislative text |
requirement_classifier.py | List of requirements (text or JSON) | Implementation matrix with types, teams, enforcement | Converting statutory obligations to actionable implementation tasks |
Canons of Statutory Construction
Complete reference for the 12 core canons used in statutory interpretation, organized by type. Each canon includes definition, explanation, example, and common misapplications.
---
Table of Contents
- Interpretation Priority
- Textual Canons
- General-Terms Canon
- Negative-Implication Canon (Expressio Unius)
- Whole-Act Rule
- Consistent Usage Presumption
- Meaningful Variation
- Surplusage Canon
- Associated Words (Noscitur a Sociis)
- Ejusdem Generis
- Purpose Canons
- Presumption Against Ineffectiveness
- Avoiding Absurdity
- Remedial Statutes Liberal Construction
- Rule of Lenity
- Interpretation Sources Hierarchy
- Applying Canons in Practice
- Canon Conflicts
---
Interpretation Priority
Before applying canons, follow this priority order:
| Priority | Source | Authority |
|---|---|---|
| 1 | Plain text of the statute | Controlling -- if clear, no further interpretation needed |
| 2 | Statutory definitions section | Controlling -- overrides ordinary meaning |
| 3 | Legislative purpose (recitals, preamble) | Strong indicator of intent |
| 4 | Canons of construction | Framework for resolving ambiguity |
| 5 | Case law interpreting the provision | Binding within jurisdiction |
| 6 | Agency regulations | Moderate authority (deference varies by jurisdiction) |
| 7 | Agency guidance and FAQs | Persuasive only, not binding |
| 8 | Legislative history | Weak to moderate (varies by jurisdiction) |
| 9 | Academic commentary | Persuasive only |
Key principle: Canons are tools for resolving genuine ambiguity. They do not override clear statutory text.
---
Textual Canons
1. General-Terms Canon
Definition: Words are to be understood in their ordinary, everyday meaning unless the statute provides a specific definition or the context clearly indicates a technical meaning.
Explanation: When a statute uses general terms without defining them, interpret those terms according to their common, accepted meaning. If the statute includes a definitions section, those definitions control -- even if they differ from ordinary usage.
Example:
- Statute says "vehicle" without defining it: interpret as any conveyance (car, truck, motorcycle, bicycle).
- Statute defines "vehicle" as "any motorized conveyance": the definition excludes bicycles even though ordinary meaning might include them.
Common misapplication: Applying technical or specialized meaning to a term when the statute uses it in its general sense, or vice versa. Always check the definitions section first.
---
2. Negative-Implication Canon (Expressio Unius)
Definition: The expression of one thing implies the exclusion of others. When a statute lists specific items without a catchall phrase, unlisted items are excluded.
Explanation: If the legislature specifically enumerated certain items, the deliberate choice to list those items and not others implies that the omitted items were intentionally excluded. This canon is strongest when the list appears exhaustive.
Example:
- Statute grants tax exemption to "hospitals, schools, and churches": museums are excluded.
- Statute applies to "dogs, cats, and ferrets": hamsters are excluded.
Common misapplication: Applying this canon to illustrative lists (those using "including" or "such as") rather than exhaustive lists. A list introduced by "including but not limited to" does not trigger this canon.
| List Type | Signal Words | Expressio Unius Applies? |
|---|---|---|
| Exhaustive | "means," "the following," "limited to" | Yes |
| Illustrative | "includes," "such as," "including but not limited to" | No |
| Ambiguous | No signal words | Context-dependent; proceed with caution |
---
3. Whole-Act Rule
Definition: A statute should be interpreted as a coherent whole. Individual provisions should be read in harmony with the entire statute, not in isolation.
Explanation: Every provision exists within a larger framework. When one section appears to conflict with another, prefer the interpretation that harmonizes both provisions. The statute's overall structure, purpose, and design inform the meaning of individual parts.
Example:
- Section 10 says "data must be deleted after processing." Section 15 says "records must be retained for 5 years." Read together: transactional data is deleted after processing, but legally required records are retained. The provisions address different categories.
Common misapplication: Cherry-picking a single provision that supports a desired outcome while ignoring other provisions that limit or qualify it. Always read cross-references, exceptions, and related sections.
---
4. Consistent Usage Presumption
Definition: When the same word or phrase is used in different parts of a statute, it presumptively carries the same meaning throughout.
Explanation: Legislatures are presumed to use language consistently. If "personal data" is defined in Article 3 and appears in Articles 5, 6, and 9, it carries the same meaning in all three articles unless the statute explicitly provides otherwise.
Example:
- GDPR defines "processing" in Article 4(2). Every use of "processing" throughout the regulation carries that definition.
- If a statute uses "shall" in one section and "must" in another without distinguishing them, they are presumed synonymous.
Common misapplication: Assuming consistent usage across different statutes. The same word may have different definitions in different legislative instruments (e.g., "personal data" in GDPR vs "personal information" in CCPA).
---
5. Meaningful Variation
Definition: When the legislature uses different words or phrases in related provisions, the variation is presumed intentional and meaningful.
Explanation: If two adjacent sections use different terms, assume the legislature chose those different terms deliberately. "Shall inform" is different from "shall notify." "Reasonable" is different from "appropriate."
Example:
- Article 33 requires "notification" to the supervisory authority within 72 hours. Article 34 requires "communication" to data subjects "without undue delay." Different words, different obligations, different timelines.
- A statute uses "employee" in Section 3 and "worker" in Section 4. These are presumed to describe different groups.
Common misapplication: Treating meaningful variation as mere stylistic choice. While drafting imperfections exist, the default presumption favors intentional variation.
---
6. Surplusage Canon
Definition: Every word in a statute is presumed to have meaning. Courts should avoid interpretations that render any word or phrase superfluous.
Explanation: If an interpretation makes certain words unnecessary or redundant, that interpretation is disfavored. The legislature is presumed not to have included meaningless language.
Example:
- Statute requires "clear and prominent" disclosure. "Clear" and "prominent" must mean different things -- "clear" relates to comprehensibility, "prominent" relates to visibility.
- If "appropriate technical and organizational measures" could be read as just "appropriate measures," the words "technical and organizational" are not surplus -- they specify the type of measures required.
Common misapplication: Taking the canon too far and manufacturing distinctions where none exist. Some statutory language is genuinely duplicative for emphasis or clarity.
---
7. Associated Words (Noscitur a Sociis)
Definition: Ambiguous words are interpreted in light of the words around them. A word's meaning is informed by its neighbors.
Explanation: When a word is ambiguous, look at the other words in the same list, sentence, or provision. The context of surrounding terms narrows the ambiguous word's meaning.
Example:
- Statute prohibits "guns, pistols, revolvers, and other dangerous weapons." The phrase "other dangerous weapons" is limited by its association with firearms -- it likely means other projectile weapons, not kitchen knives.
- A provision applies to "banks, credit unions, and similar financial institutions." "Similar financial institutions" is limited by association with deposit-taking entities.
Common misapplication: Using associated words to narrow a term that the legislature clearly intended to be broad. If the list is explicitly illustrative ("including but not limited to"), the associated-words canon has less force.
---
8. Ejusdem Generis
Definition: When a general term follows a list of specific terms, the general term is limited to items of the same kind as the specific terms.
Explanation: This is a specific application of the associated-words canon. A catchall phrase ("and other similar...") following a list of specifics is constrained by the nature of the listed items.
Example:
- "Automobiles, trucks, motorcycles, and other vehicles" -- "other vehicles" likely means motorized road vehicles, not aircraft or boats.
- "Fraud, embezzlement, theft, and other dishonest acts" -- "other dishonest acts" is limited to acts similar in nature to fraud, embezzlement, and theft.
Common misapplication: Applying ejusdem generis when there is no common genus. If the listed items are diverse and share no common characteristic, the general term may genuinely be broad.
| Scenario | Listed Items | General Term | Ejusdem Generis Applies? |
|---|---|---|---|
| Common genus exists | "dogs, cats, hamsters" | "and other animals" | Yes -- likely means domestic pets |
| No common genus | "land, money, vehicles, intellectual property" | "and other assets" | Weak -- items too diverse to constrain |
| Explicit breadth | "any device or technology" | n/a | No -- no specific list to constrain |
---
Purpose Canons
9. Presumption Against Ineffectiveness
Definition: Between two possible readings of a statute, prefer the one that gives the provision actual legal effect over the one that renders it meaningless or ineffective.
Explanation: Legislatures do not enact provisions intended to have no effect. If one interpretation makes a provision operational and another makes it a dead letter, choose the operational reading.
Example:
- A requirement to "implement appropriate security measures" can be read as either (a) a substantive obligation requiring actual security controls, or (b) a vague aspiration with no enforceable content. Prefer reading (a).
Common misapplication: Using this canon to expand a provision beyond its natural scope simply to give it "more" effect. The canon prevents nullification, not expansion.
---
10. Avoiding Absurdity
Definition: A statute should not be interpreted to produce absurd or unreasonable results if a sensible alternative interpretation exists.
Explanation: If the literal reading of a statute produces an outcome that no reasonable legislature would have intended, courts may depart from the literal text in favor of a reasonable interpretation. This canon is applied sparingly.
Example:
- A statute requires breach notification "within 72 hours of becoming aware of the breach." Literal reading might mean 72 hours from the moment any employee notices anything unusual. Reasonable reading: 72 hours from when the organization reasonably confirms a notifiable breach has occurred.
Common misapplication: Using "absurdity" as a cover for disagreeing with the statute's policy. The canon addresses genuinely irrational outcomes, not outcomes the reader finds undesirable.
---
11. Remedial Statutes Liberal Construction
Definition: Statutes designed to protect consumers, employees, the public, or other vulnerable groups should be construed liberally to advance their protective purpose.
Explanation: Consumer protection, environmental, and safety statutes are read broadly to achieve their remedial goals. Ambiguities are resolved in favor of the protected class.
Example:
- GDPR is a data protection statute. Ambiguities about scope should generally be resolved in favor of protecting data subjects.
- Employment discrimination statutes are construed broadly to cover more situations, not fewer.
Common misapplication: Applying liberal construction to override clear statutory limitations. Even remedial statutes have defined scope -- liberal construction operates within that scope, not beyond it.
---
12. Rule of Lenity
Definition: In criminal statutes or provisions imposing penalties, ambiguity is resolved in favor of the person subject to the penalty.
Explanation: When a penal provision is genuinely ambiguous -- where two reasonable readings exist -- the less punitive reading applies. This reflects the principle that individuals should have fair notice of what conduct is prohibited.
Example:
- A statute imposes fines for "unauthorized processing." If it is genuinely unclear whether a specific type of processing is "unauthorized," the ambiguity should be resolved against finding a violation.
Common misapplication: Invoking lenity when the statute is not genuinely ambiguous, or applying it to civil regulatory provisions that are not penal in nature.
| Provision Type | Lenity Applies? |
|---|---|
| Criminal sanctions | Yes |
| Administrative fines | Yes (in most jurisdictions) |
| Civil liability | Generally no |
| Regulatory obligations | Generally no |
| Injunctive relief | Generally no |
---
Interpretation Sources Hierarchy
When canons alone do not resolve ambiguity, consult external sources in this order:
| Source | Use When | Reliability |
|---|---|---|
| Statutory text (other provisions) | Always -- the best context is the statute itself | Highest |
| Recitals / Preamble | Purpose is unclear from operative text | High for EU law; moderate elsewhere |
| Implementing regulations | Statute delegates detail to regulations | High within delegated authority |
| Case law | Courts have interpreted the provision | High within jurisdiction |
| Agency guidance | Agency has published interpretation | Moderate -- persuasive, not binding |
| Legislative history | Text is genuinely ambiguous | Low in textualist jurisdictions; moderate in purposivist |
| Academic commentary | Novel question with no authoritative guidance | Low -- persuasive only |
---
Applying Canons in Practice
Step-by-Step Process
1. Read the plain text. If clear and unambiguous, stop. The plain text controls. 2. Check the definitions section. Statutory definitions override ordinary meaning. 3. Read surrounding provisions. Apply the whole-act rule. 4. Identify the ambiguity. Precisely articulate what is unclear and why. 5. Apply relevant canons. Usually, more than one canon will be relevant. 6. Check for canon conflicts. Canons may point in different directions. 7. Consult external sources. Case law, regulations, guidance, in priority order. 8. Document your reasoning. Record which canons you applied and why.
---
Canon Conflicts
Canons can conflict. When they do, use this resolution framework:
| Conflict | Resolution |
|---|---|
| Textual canon vs textual canon | Weight both; consider which has stronger textual support |
| Textual canon vs purpose canon | Textual canons generally prevail; purpose canons are tiebreakers |
| Expressio unius vs ejusdem generis | Determine whether the list is exhaustive (expressio unius) or followed by a catchall (ejusdem generis) |
| Consistent usage vs meaningful variation | Determine whether the legislature used different terms deliberately or carelessly |
| Surplusage vs absurdity | If giving every word meaning produces absurdity, absurdity canon prevails |
| Lenity vs remedial statute | Context-dependent: penal provisions get lenity, protective provisions get liberal construction |
Overarching principle: No single canon is dispositive. Canons are interpretive tools, not rigid rules. The strongest interpretation is one supported by multiple canons pointing the same direction.
Statutory Structure Reference
How statutes and regulations are organized, read, and navigated. Covers structural hierarchy, definitions sections, effective dates, preemption, cross-references, enforcement, and the "what the statute doesn't say" checklist.
---
Table of Contents
- Structural Hierarchy
- Finding and Reading Definitions
- Effective Dates and Transitional Provisions
- Amendments and Consolidated Versions
- Preemption Analysis
- Cross-Reference Tracking
- Common Threshold Types
- Enforcement Analysis
- What the Statute Does Not Say
---
Structural Hierarchy
Statutes follow a nested hierarchy. Understanding this structure is essential for precise citation and navigation.
US Federal Statutes (United States Code)
| Level | Label | Example |
|---|---|---|
| Title | Major subject area | Title 15 -- Commerce and Trade |
| Chapter | Subdivision of title | Chapter 98 -- CAN-SPAM |
| Subchapter | Subdivision of chapter | Subchapter I -- General Provisions |
| Section (§) | Individual provision | § 7702 -- Definitions |
| Subsection | Lettered subdivision | § 7702(a) |
| Paragraph | Numbered subdivision | § 7702(a)(1) |
| Subparagraph | Lettered sub-subdivision | § 7702(a)(1)(A) |
| Clause | Roman-numeral subdivision | § 7702(a)(1)(A)(i) |
US Federal Regulations (Code of Federal Regulations)
| Level | Label | Example |
|---|---|---|
| Title | Subject area | Title 16 -- Commercial Practices |
| Chapter | Agency | Chapter I -- Federal Trade Commission |
| Subchapter | Topic area | Subchapter C -- Regulations |
| Part | Specific regulation | Part 312 -- COPPA Rule |
| Subpart | Subdivision of part | Subpart A -- General Provisions |
| Section (§) | Individual provision | § 312.2 -- Definitions |
EU Legislation
| Level | Label | Example (GDPR) |
|---|---|---|
| Recitals | Interpretive context (numbered) | Recital (26) -- Anonymous data |
| Chapter | Major division | Chapter II -- Principles |
| Section | Subdivision of chapter | Section 1 -- Transparency |
| Article | Individual provision | Article 5 -- Principles relating to processing |
| Paragraph | Numbered subdivision | Article 5(1) |
| Point/Letter | Lettered subdivision | Article 5(1)(a) |
| Sub-point | Roman numeral | Article 5(1)(a)(i) |
UK Legislation
| Level | Label | Example |
|---|---|---|
| Part | Major division | Part 2 -- General processing |
| Chapter | Subdivision of part | Chapter 2 -- The GDPR |
| Section | Individual provision | Section 6 -- The applied GDPR |
| Subsection | Numbered subdivision | Section 6(1) |
| Paragraph | Lettered subdivision | Section 6(1)(a) |
| Schedule | Supplementary material | Schedule 1 -- Special categories of personal data |
---
Finding and Reading Definitions
Where Definitions Appear
| Statute Type | Typical Location | Example |
|---|---|---|
| US federal statute | First section of the chapter/title | 15 USC § 7702 (CAN-SPAM definitions) |
| US federal regulation | First section of the part | 16 CFR § 312.2 (COPPA definitions) |
| EU regulation | Early articles (usually Art. 2-4) | GDPR Art. 4 (26 definitions) |
| UK statute | Interpretation section near the end | Data Protection Act 2018 s.3-5 |
Definition Types
| Signal | Type | Scope |
|---|---|---|
| "'X' means..." | Exhaustive | The definition is complete; no other meaning applies |
| "'X' includes..." | Illustrative | Examples listed but meaning extends beyond them |
| "'X' does not include..." | Exclusion | Specific items removed from scope |
| "'X' refers to..." | Pointer | Incorporates a definition from another source |
| "For the purposes of this Section..." | Scoped | Definition applies only to specified provisions |
| "Unless the context otherwise requires..." | Contextual | Definition is default but can be overridden by context |
Reading Strategy
1. Read definitions first before reading substantive provisions. 2. Map defined terms to their operative provisions. 3. Check for scoped definitions -- some terms are redefined for specific sections. 4. Note incorporated definitions -- terms defined by reference to other instruments. 5. Watch for undefined terms -- apply the general-terms canon (ordinary meaning).
---
Effective Dates and Transitional Provisions
Effective Date Patterns
| Pattern | Meaning | Example |
|---|---|---|
| "This Act enters into force on [date]" | All provisions effective on stated date | Simple effective date |
| "This Regulation shall apply from [date]" | EU pattern: enters into force 20 days after publication but applies from later date | GDPR: entered into force May 2016, applied from May 2018 |
| Phased effective dates | Different provisions effective at different times | EU AI Act: prohibited practices Feb 2025, high-risk Aug 2026 |
| "Within [X] months of entry into force" | Delegated acts or implementing measures due by deadline | Agency must publish rules within 12 months |
| Sunset clause | Provision expires on stated date | Temporary measures, emergency powers |
Transitional Provisions
| Type | Purpose | Example |
|---|---|---|
| Grandfathering | Existing activities continue under old rules | "Systems placed on the market before [date] remain subject to [old requirement]" |
| Grace period | Time to achieve compliance | "Entities shall comply within 24 months of entry into force" |
| Phase-in | Gradual application by category | Small enterprises: 36 months; large enterprises: 24 months |
| Saving clause | Preserves rights/obligations from prior law | "Proceedings commenced under [old law] shall continue under [old law]" |
Compliance Timeline Construction
1. Identify the statute's entry-into-force date. 2. List each provision with its specific effective date (if phased). 3. Identify any transitional provisions that modify timing. 4. Check for delegated acts with their own timelines. 5. Map deadlines to a calendar and assign compliance owners.
---
Amendments and Consolidated Versions
Types of Amendments
| Type | Effect | How to Identify |
|---|---|---|
| Textual amendment | Replaces specific words in the original | "In Article X, replace 'Y' with 'Z'" |
| Insertion | Adds new provisions | "After Article X, insert Article X-a" |
| Repeal | Removes provision entirely | "Article X is repealed" |
| Substitution | Replaces entire section | "For Article X, substitute the following" |
Finding Current Law
| Jurisdiction | Consolidated Source | Notes |
|---|---|---|
| US federal | United States Code (uscode.house.gov) | Official codification; updated regularly |
| US regulations | eCFR (ecfr.gov) | Updated daily; not official but authoritative |
| EU | EUR-Lex consolidated text | Marked "only for reference"; check latest OJ for amendments |
| UK | legislation.gov.uk | Shows amendments with tracked changes |
Warning: Always verify you are reading the current, in-force version. Citing repealed or amended provisions is a common error.
---
Preemption Analysis
Preemption determines which law controls when multiple jurisdictions overlap.
US Federal-State Preemption
| Type | Definition | Example |
|---|---|---|
| Express preemption | Federal statute explicitly preempts state law | "No State shall maintain... any requirement different from" |
| Implied preemption (field) | Federal scheme is so comprehensive it occupies the entire field | Immigration law |
| Implied preemption (conflict) | Compliance with both federal and state law is impossible | State law requires what federal law prohibits |
| Floor preemption | Federal law sets a minimum; states may go higher | CCPA exceeds federal privacy protections |
| Ceiling preemption | Federal law sets a maximum; states may not exceed | Federal banking regulations |
EU Preemption
| Instrument | Preemptive Effect |
|---|---|
| Regulation | Directly applicable; generally preempts conflicting member state law |
| Directive | Sets minimum standards; member states transpose with possible additions |
| Regulation with member state margin | Regulation but explicitly allows member state variation (e.g., GDPR Art. 9(4)) |
Preemption Checklist
1. Does the statute contain an express preemption clause? (Read it carefully -- scope matters.) 2. Does the statute contain a savings clause preserving other laws? (Common in consumer protection.) 3. Is the federal scheme comprehensive enough to imply field preemption? 4. Can an entity comply with both laws simultaneously? 5. Does the statute set a floor or a ceiling?
---
Cross-Reference Tracking
Types of Cross-References
| Type | Example | Interpretation |
|---|---|---|
| Definitional | "as defined in Article 4" | Imports the definition |
| Qualifying | "subject to Article 23" | Another provision limits or modifies this one |
| Supplementing | "in addition to the requirements of Article 9" | Both provisions apply cumulatively |
| Override | "notwithstanding Article 15" | This provision prevails over Article 15 |
| Conditional | "where Article 6(1)(a) applies" | Triggered only when the referenced condition exists |
| External | "as referred to in Directive 2001/95/EC" | Imports requirements from a different instrument |
Cross-Reference Resolution Process
1. Read the target provision. 2. Identify every cross-reference within it. 3. Read each referenced provision in full. 4. Classify each cross-reference (qualifying, supplementing, override, etc.). 5. Check for chains: does the referenced provision reference yet another? 6. Document the complete picture: the target provision plus all modifications. 7. Watch for circular references -- they exist and create genuine ambiguity.
---
Common Threshold Types
Many statutes create obligations that apply only when certain thresholds are met.
| Threshold Type | Examples | Analysis |
|---|---|---|
| Revenue/turnover | "Businesses with annual revenue exceeding $25 million" (CCPA) | Determine calculation method (gross vs net, calendar vs fiscal year) |
| Volume | "Processes personal data of 100,000+ consumers annually" (CCPA) | Determine counting methodology |
| Employee count | "Employers with 50 or more employees" (FMLA) | Check if part-time counts; check geographic scope |
| Entity type | "Financial institutions," "covered entities" | Read the definition precisely; check for exclusions |
| Geographic | "Entities established in the Union" or "offering goods to EU residents" | Both establishment and targeting tests may apply |
| Data type | "Special categories of personal data" (GDPR Art. 9) | Exhaustive list -- only the enumerated categories qualify |
| Risk level | "High-risk AI system" (EU AI Act Art. 6) | Follow the classification decision tree precisely |
Conjunctive vs Disjunctive Thresholds
| Statute Pattern | Reading | Impact |
|---|---|---|
| "Revenue > $25M AND processes data of > 100K consumers" | Must meet BOTH thresholds | Narrower scope |
| "Revenue > $25M OR processes data of > 100K consumers" | Must meet EITHER threshold | Broader scope |
| "Revenue > $25M, and processes data of > 100K consumers, or derives 50%+ of revenue from selling data" | First two conjunctive, third disjunctive | Parse structure carefully |
---
Enforcement Analysis
For each statutory requirement, assess enforcement risk using these factors.
Enforcement Authority
| Factor | Questions to Ask |
|---|---|
| Which agency enforces? | Primary regulator and any concurrent enforcement authority |
| How active is the agency? | Enforcement actions per year, budget, staffing trends |
| Is there a dedicated enforcement unit? | Specialized teams signal enforcement priority |
| What enforcement tools exist? | Investigation, subpoena, administrative proceedings, litigation |
Penalty Types
| Type | Characteristics | Examples |
|---|---|---|
| Civil fines | Administrative penalties; no criminal record | GDPR: up to EUR 20M or 4% of turnover |
| Criminal penalties | Prosecution, imprisonment, criminal record | US: willful violations of certain statutes |
| Administrative sanctions | Orders, bans, suspensions | Cease processing orders, license suspension |
| Private right of action | Individuals can sue directly | CCPA: $100-$750 per consumer per incident |
| Injunctive relief | Court-ordered cessation of conduct | Temporary or permanent injunctions |
Enforcement Risk Matrix
| Factor | Low Risk | Medium Risk | High Risk |
|---|---|---|---|
| Enforcement history | Few or no actions | Regular actions in the area | Active enforcement campaign |
| Penalty severity | Low fixed fines | Material fines | Revenue-based penalties |
| Private right of action | No | Limited | Broad with statutory damages |
| Cure period | Extended cure period | Short cure period | No cure period |
| Regulatory guidance | Clear and favorable | Ambiguous | Unfavorable or absent |
---
What the Statute Does Not Say
A critical part of statutory analysis is identifying what the statute omits. Silence can mean permission, delegation, oversight, or ambiguity.
10-Point Checklist
| # | Check | Why It Matters |
|---|---|---|
| 1 | Does the statute define this term? | If not defined, ordinary meaning applies -- which may be broader or narrower than expected |
| 2 | Does the statute address this specific scenario? | If the statute is silent on a scenario, it may be permissible, delegated to regulation, or an oversight |
| 3 | Is there an explicit exception for this activity? | Absence of an exception may mean the general rule applies -- or that the legislature did not contemplate the activity |
| 4 | Does the statute specify a method or standard? | Silence on method may mean any reasonable method is acceptable |
| 5 | Does the statute set a numerical threshold? | Absence of a threshold may mean the obligation applies universally or that threshold is delegated |
| 6 | Does the statute name an enforcement authority? | No named enforcer may mean general enforcement powers or no enforcement mechanism |
| 7 | Does the statute provide a private right of action? | Silence on private action generally means no private right (courts will not imply one) |
| 8 | Does the statute address cross-border application? | Silence on extraterritoriality creates uncertainty -- analyze based on jurisdiction principles |
| 9 | Does the statute address conflicts with other laws? | No preemption or savings clause creates ambiguity about which law prevails |
| 10 | Does the statute provide for future regulatory development? | Delegation clauses signal that key details will come in later regulations |
Interpreting Statutory Silence
| Possible Meaning | How to Determine | Action |
|---|---|---|
| Permission | Expressio unius: specific prohibitions listed, this activity not among them | Document reasoning; monitor for future amendments |
| Delegation | Statute grants agency authority to "prescribe rules" or "establish requirements" | Check for implementing regulations |
| Oversight | Legislature did not consider this scenario | Flag as gap; seek analogous provisions or guidance |
| Intentional ambiguity | Legislature could not agree on specifics | Document ambiguity; seek case law or agency interpretation |
| Deference to other law | Another body of law already covers this | Identify the applicable law |
#!/usr/bin/env python3
"""
Requirement Classifier
Takes statutory requirements (from text or JSON) and classifies each by type,
implementation team, enforcement mechanism, and penalty type. Generates an
implementation matrix for compliance planning.
Usage:
python requirement_classifier.py --input requirements.json
python requirement_classifier.py --text "Controllers must provide a privacy notice..."
python requirement_classifier.py --input requirements.json --json
python requirement_classifier.py --input requirements.json --output matrix.json
Input JSON schema (list of requirements):
[
{"id": "R-001", "text": "The controller shall provide..."},
{"id": "R-002", "text": "Data subjects have the right to..."}
]
Or plain text with one requirement per line.
"""
import argparse
import json
import re
import sys
from typing import Any, Dict, List, Optional, Tuple
# Requirement type classification patterns
TYPE_PATTERNS: List[Tuple[str, List[str], str]] = [
("disclosure", [
r"\bprovide\s+(?:information|notice|notification|disclosure)",
r"\binform\b", r"\bnotif(?:y|ication)\b", r"\btransparenc(?:y|t)\b",
r"\bprivacy\s+(?:notice|policy)\b", r"\bdisclose\b",
r"\bmake\s+available\b", r"\bpubli(?:sh|c)\b",
], "Information must be provided to someone"),
("operational", [
r"\bimplement\b", r"\bestablish\b", r"\bmaintain\b",
r"\bprocess(?:es|ing)?\b", r"\bprocedure\b", r"\bpolic(?:y|ies)\b",
r"\brecord[- ]?keep", r"\blog(?:ging|s)?\b", r"\baudit\b",
r"\breview\b", r"\bmonitor\b", r"\bensure\b",
], "Process or procedure must exist"),
("technical", [
r"\bencrypt(?:ion)?\b", r"\baccess\s+control", r"\bpseudonymis",
r"\btechnical\s+measure", r"\bsecurit(?:y|ies)\b", r"\bfirewall\b",
r"\bauthenticat(?:e|ion)\b", r"\bbackup\b", r"\bdata\s+(?:integrity|protection)",
r"\bcybersecurity\b", r"\bsafeguard\b",
], "System capability or safeguard required"),
("ui_design", [
r"\bconsent\s+(?:mechanism|form|button|dialog)", r"\bopt[- ](?:in|out)\b",
r"\buser\s+interface\b", r"\bcookie\s+(?:banner|notice)\b",
r"\bpreference\s+(?:center|setting)", r"\btoggle\b",
r"\bcheckbox\b", r"\bvisual(?:ly)?\s+(?:display|present|prominent)",
], "User interface must include specific elements"),
("organizational", [
r"\bappoint\b", r"\bdesignat(?:e|ion)\b", r"\bofficer\b",
r"\bboard\b", r"\bgovernance\b", r"\bcommittee\b",
r"\bresponsib(?:le|ility)\b", r"\baccountab(?:le|ility)\b",
r"\brole\b", r"\btraining\b", r"\bawareness\b",
], "Governance structure or role required"),
("documentation", [
r"\bdocument(?:ation|ed)?\b", r"\brecord\b", r"\bimpact\s+assessment\b",
r"\brisk\s+assessment\b", r"\bdata\s+protection\s+impact",
r"\bwritten\b", r"\breport\b", r"\bregist(?:er|ration)\b",
], "Written records must be maintained"),
("reporting", [
r"\breport\s+to\b", r"\bnotif(?:y|ication)\s+(?:to\s+)?(?:the\s+)?(?:authority|supervisor|regulator)",
r"\bsubmit\b", r"\bfile\s+(?:with|to)\b", r"\bannual\s+report\b",
r"\bbreach\s+notification\b", r"\bincident\s+report",
], "Information must be submitted to authority"),
]
# Implementation team patterns
TEAM_PATTERNS: List[Tuple[str, List[str]]] = [
("legal", [
r"\blegal\b", r"\bcompliance\b", r"\bcontract", r"\bliabilit",
r"\bdisclaimer\b", r"\bterms\b", r"\blawful\b", r"\blegal\s+basis",
]),
("engineering", [
r"\btechnical\b", r"\bsystem\b", r"\bimplement\b", r"\bencrypt",
r"\baccess\s+control", r"\bapi\b", r"\bsoftware\b", r"\barchitect",
r"\binfrastructure\b", r"\bautomated\b",
]),
("product", [
r"\buser\s+(?:interface|experience)\b", r"\bdesign\b", r"\bfeature\b",
r"\bconsent\b", r"\bopt[- ](?:in|out)\b", r"\bpreference\b",
r"\bdashboard\b", r"\bsetting\b",
]),
("compliance", [
r"\baudit\b", r"\bmonitor\b", r"\bassess\b", r"\breview\b",
r"\bpolic(?:y|ies)\b", r"\bprocedure\b", r"\brecord\b",
r"\brisk\b", r"\bgovernance\b",
]),
("security", [
r"\bsecurit(?:y|ies)\b", r"\bcybersecurity\b", r"\bbreach\b",
r"\bincident\b", r"\bthreat\b", r"\bvulnerabilit", r"\bpenetration",
]),
("hr", [
r"\btraining\b", r"\bawareness\b", r"\bstaff\b", r"\bpersonnel\b",
r"\bemployee\b", r"\bhir(?:e|ing)\b", r"\brole\b",
]),
("management", [
r"\bboard\b", r"\bsenior\s+management\b", r"\bgovernance\b",
r"\bappoint\b", r"\boversight\b", r"\baccountab",
]),
]
# Enforcement mechanism patterns
ENFORCEMENT_PATTERNS: Dict[str, List[str]] = {
"administrative_fine": [
r"\bfine\b", r"\bpenalt(?:y|ies)\b", r"\badministrative\s+(?:fine|sanction)",
r"\bmonetary\b", r"\b(?:EUR|USD|\$|€)\s*\d",
],
"criminal": [
r"\bcriminal\b", r"\bimprisonment\b", r"\boffence\b", r"\boffense\b",
r"\bprosecuti", r"\bfelony\b", r"\bmisdemeanor\b",
],
"civil_liability": [
r"\bliab(?:le|ility)\b", r"\bdamages\b", r"\bcompensati",
r"\bcivil\b", r"\bclaim\b", r"\bright\s+of\s+action\b",
],
"injunction": [
r"\binjuncti", r"\bcease\b", r"\bsuspend\b", r"\bprohibit\b",
r"\brestraining\s+order\b", r"\bban\b",
],
"license_revocation": [
r"\brevok(?:e|ation)\b", r"\bsuspend\b", r"\bwithdr(?:aw|awal)\b",
r"\blicen(?:s|c)e\b", r"\bauthori[sz]ation\b",
],
"audit_investigation": [
r"\baudit\b", r"\binvestigat\b", r"\binspect\b", r"\bexamin",
],
}
# Priority keywords
PRIORITY_KEYWORDS: Dict[str, List[str]] = {
"critical": [r"\bimmediately\b", r"\bwithout delay\b", r"\bprohibit\b", r"\bban\b"],
"high": [r"\bshall\b", r"\bmust\b", r"\brequired\b", r"\bmandatory\b"],
"medium": [r"\bshould\b", r"\bexpected\b", r"\brecommend\b"],
"low": [r"\bmay\b", r"\boptional\b", r"\bconsider\b"],
}
def classify_type(text: str) -> Tuple[str, str, float]:
"""Classify requirement type. Returns (type, description, confidence)."""
text_lower = text.lower()
scores: Dict[str, int] = {}
desc_map: Dict[str, str] = {}
for type_name, patterns, description in TYPE_PATTERNS:
score = 0
for p in patterns:
if re.search(p, text_lower):
score += 1
if score > 0:
scores[type_name] = score
desc_map[type_name] = description
if not scores:
return "general", "General requirement", 0.3
best = max(scores, key=scores.get)
confidence = min(scores[best] / 3.0, 1.0)
return best, desc_map[best], round(confidence, 2)
def classify_team(text: str) -> List[str]:
"""Identify implementation teams."""
text_lower = text.lower()
teams = []
for team_name, patterns in TEAM_PATTERNS:
for p in patterns:
if re.search(p, text_lower):
teams.append(team_name)
break
return teams if teams else ["compliance"]
def classify_enforcement(text: str) -> List[str]:
"""Identify enforcement mechanisms."""
text_lower = text.lower()
mechanisms = []
for mechanism, patterns in ENFORCEMENT_PATTERNS.items():
for p in patterns:
if re.search(p, text_lower):
mechanisms.append(mechanism)
break
return mechanisms if mechanisms else ["unspecified"]
def classify_priority(text: str) -> str:
"""Determine requirement priority."""
text_lower = text.lower()
for priority, patterns in PRIORITY_KEYWORDS.items():
for p in patterns:
if re.search(p, text_lower):
return priority
return "medium"
def extract_deadline_indicators(text: str) -> Optional[str]:
"""Extract deadline-related language."""
patterns = [
r"within\s+\d+\s+(?:days?|months?|years?|hours?)",
r"no\s+later\s+than\s+[\w\s,]+",
r"by\s+\d{1,2}\s+\w+\s+\d{4}",
r"before\s+[\w\s,]+\d{4}",
r"(?:immediately|without\s+(?:undue\s+)?delay)",
]
for p in patterns:
m = re.search(p, text, re.IGNORECASE)
if m:
return m.group().strip()
return None
def classify_requirement(req_id: str, text: str) -> Dict[str, Any]:
"""Classify a single requirement."""
req_type, type_desc, confidence = classify_type(text)
teams = classify_team(text)
enforcement = classify_enforcement(text)
priority = classify_priority(text)
deadline = extract_deadline_indicators(text)
return {
"id": req_id,
"text": text.strip(),
"classification": {
"type": req_type,
"type_description": type_desc,
"confidence": confidence,
},
"implementation": {
"teams": teams,
"primary_team": teams[0] if teams else "compliance",
},
"enforcement": {
"mechanisms": enforcement,
},
"priority": priority,
"deadline_indicator": deadline,
}
def parse_input(text: str) -> List[Dict[str, str]]:
"""Parse input as JSON list or plain text (one requirement per line)."""
text = text.strip()
if text.startswith("["):
try:
data = json.loads(text)
if isinstance(data, list):
result = []
for i, item in enumerate(data):
if isinstance(item, dict):
req_id = item.get("id", f"R-{i+1:03d}")
req_text = item.get("text", str(item))
else:
req_id = f"R-{i+1:03d}"
req_text = str(item)
result.append({"id": req_id, "text": req_text})
return result
except json.JSONDecodeError:
pass
# Plain text: one requirement per line
lines = [line.strip() for line in text.split("\n") if line.strip()]
return [{"id": f"R-{i+1:03d}", "text": line} for i, line in enumerate(lines)]
def compute_matrix_summary(classified: List[Dict]) -> Dict[str, Any]:
"""Compute summary statistics for the implementation matrix."""
type_counts: Dict[str, int] = {}
team_counts: Dict[str, int] = {}
priority_counts: Dict[str, int] = {}
enforcement_counts: Dict[str, int] = {}
for req in classified:
t = req["classification"]["type"]
type_counts[t] = type_counts.get(t, 0) + 1
for team in req["implementation"]["teams"]:
team_counts[team] = team_counts.get(team, 0) + 1
p = req["priority"]
priority_counts[p] = priority_counts.get(p, 0) + 1
for e in req["enforcement"]["mechanisms"]:
enforcement_counts[e] = enforcement_counts.get(e, 0) + 1
return {
"total_requirements": len(classified),
"by_type": dict(sorted(type_counts.items(), key=lambda x: -x[1])),
"by_team": dict(sorted(team_counts.items(), key=lambda x: -x[1])),
"by_priority": dict(sorted(priority_counts.items(), key=lambda x: -x[1])),
"by_enforcement": dict(sorted(enforcement_counts.items(), key=lambda x: -x[1])),
}
def format_human_report(classified: List[Dict], summary: Dict) -> str:
"""Format results as human-readable report."""
lines = []
lines.append("=" * 72)
lines.append("REQUIREMENT CLASSIFICATION MATRIX")
lines.append("=" * 72)
lines.append(f"\nTotal requirements: {summary['total_requirements']}")
lines.append("\n--- BY TYPE ---")
for t, c in summary["by_type"].items():
lines.append(f" {t:20s} {c:4d}")
lines.append("\n--- BY TEAM ---")
for t, c in summary["by_team"].items():
lines.append(f" {t:20s} {c:4d}")
lines.append("\n--- BY PRIORITY ---")
for p, c in summary["by_priority"].items():
lines.append(f" {p:20s} {c:4d}")
lines.append("\n--- REQUIREMENTS ---")
for req in classified:
lines.append(f"\n [{req['id']}] ({req['priority'].upper()})")
lines.append(f" Text: {req['text'][:150]}")
lines.append(f" Type: {req['classification']['type']} ({req['classification']['confidence']:.0%})")
lines.append(f" Teams: {', '.join(req['implementation']['teams'])}")
lines.append(f" Enforcement: {', '.join(req['enforcement']['mechanisms'])}")
if req["deadline_indicator"]:
lines.append(f" Deadline: {req['deadline_indicator']}")
lines.append("\n" + "=" * 72)
return "\n".join(lines)
def main() -> None:
parser = argparse.ArgumentParser(
description="Classify statutory requirements by type, team, enforcement, and priority."
)
parser.add_argument("--input", "-i", type=str, help="Path to requirements file (JSON or text)")
parser.add_argument("--text", "-t", type=str, help="Inline requirement text")
parser.add_argument("--output", "-o", type=str, help="Path to save output (JSON)")
parser.add_argument("--json", action="store_true", help="Output in JSON format")
args = parser.parse_args()
if not args.input and not args.text:
parser.print_help()
sys.exit(1)
try:
if args.input:
with open(args.input, "r", encoding="utf-8") as f:
raw = f.read()
else:
raw = args.text
if not raw or not raw.strip():
print("Error: Empty input.", file=sys.stderr)
sys.exit(1)
requirements = parse_input(raw)
classified = [classify_requirement(r["id"], r["text"]) for r in requirements]
summary = compute_matrix_summary(classified)
result = {
"summary": summary,
"requirements": classified,
}
if args.output:
with open(args.output, "w", encoding="utf-8") as f:
json.dump(result, f, indent=2, ensure_ascii=False)
print(f"Matrix saved to {args.output}")
elif args.json:
print(json.dumps(result, indent=2, ensure_ascii=False))
else:
print(format_human_report(classified, summary))
except FileNotFoundError:
print(f"Error: File not found: {args.input}", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Statute Keyword Analyzer
Scans statute or regulation text for operative keywords and classifies them
into obligations, permissions, conditions, exemptions, definitions, and
cross-references. Produces a structured map of legal requirements.
Usage:
python statute_keyword_analyzer.py --input statute.txt
python statute_keyword_analyzer.py --text "The controller shall implement..."
python statute_keyword_analyzer.py --input statute.txt --json
python statute_keyword_analyzer.py --input statute.txt --output report.json
"""
import argparse
import json
import re
import sys
from collections import Counter
from typing import Any, Dict, List, Tuple
# Keyword classification patterns
KEYWORD_PATTERNS: Dict[str, List[Dict[str, Any]]] = {
"mandatory": [
{"pattern": r"\bshall\b", "keyword": "shall", "description": "Creates an obligation"},
{"pattern": r"\bmust\b", "keyword": "must", "description": "Creates an obligation"},
{"pattern": r"\bis required to\b", "keyword": "is required to", "description": "Creates an obligation"},
{"pattern": r"\bis obliged to\b", "keyword": "is obliged to", "description": "Creates an obligation"},
],
"permissive": [
{"pattern": r"\bmay\b(?!\s+not\b)", "keyword": "may", "description": "Creates permission"},
{"pattern": r"\bis entitled to\b", "keyword": "is entitled to", "description": "Creates an entitlement"},
{"pattern": r"\bhas the right to\b", "keyword": "has the right to", "description": "Creates a right"},
],
"prohibitive": [
{"pattern": r"\bmay not\b", "keyword": "may not", "description": "Creates a prohibition"},
{"pattern": r"\bshall not\b", "keyword": "shall not", "description": "Creates a prohibition"},
{"pattern": r"\bmust not\b", "keyword": "must not", "description": "Creates a prohibition"},
{"pattern": r"\bis prohibited\b", "keyword": "is prohibited", "description": "Creates a prohibition"},
{"pattern": r"\bno\s+\w+\s+shall\b", "keyword": "no...shall", "description": "Negative obligation"},
],
"exception": [
{"pattern": r"\bunless\b", "keyword": "unless", "description": "Negates rule when condition met"},
{"pattern": r"\bexcept\b", "keyword": "except", "description": "Carves out specific items"},
{"pattern": r"\bprovided that\b", "keyword": "provided that", "description": "Adds a condition"},
{"pattern": r"\bexempt(?:ed|ion)?\b", "keyword": "exempt/exemption", "description": "Carves out from scope"},
{"pattern": r"\bexclud(?:e[ds]?|ing)\b", "keyword": "exclude", "description": "Removes from scope"},
],
"conditional": [
{"pattern": r"\bsubject to\b", "keyword": "subject to", "description": "Another provision modifies this"},
{"pattern": r"\bif\b", "keyword": "if", "description": "Trigger condition"},
{"pattern": r"\bwhere\b", "keyword": "where", "description": "Conditional clause"},
{"pattern": r"\bupon\b", "keyword": "upon", "description": "Temporal trigger"},
{"pattern": r"\bprovided that\b", "keyword": "provided that", "description": "Conditional requirement"},
{"pattern": r"\bin the event\b", "keyword": "in the event", "description": "Contingency trigger"},
],
"override": [
{"pattern": r"\bnotwithstanding\b", "keyword": "notwithstanding", "description": "This prevails over conflicting provisions"},
{"pattern": r"\bprevail[s]?\s+over\b", "keyword": "prevails over", "description": "Priority clause"},
{"pattern": r"\bwithout prejudice to\b", "keyword": "without prejudice to", "description": "Preserves another provision's effect"},
],
"definition": [
{"pattern": r"['\u2018]\w[^'\u2019]*['\u2019]\s+means\b", "keyword": "'X' means", "description": "Exhaustive definition"},
{"pattern": r"['\u2018]\w[^'\u2019]*['\u2019]\s+includes\b", "keyword": "'X' includes", "description": "Illustrative definition"},
{"pattern": r"['\u2018]\w[^'\u2019]*['\u2019]\s+refers to\b", "keyword": "'X' refers to", "description": "Pointer definition"},
{"pattern": r"\bfor the purposes of\b", "keyword": "for the purposes of", "description": "Scoped definition"},
{"pattern": r"\bas defined in\b", "keyword": "as defined in", "description": "Cross-reference definition"},
],
"conjunctive_disjunctive": [
{"pattern": r"\band/or\b", "keyword": "and/or", "description": "Ambiguous conjunctive/disjunctive"},
{"pattern": r"\bboth\s+\w+\s+and\b", "keyword": "both...and", "description": "Explicitly conjunctive"},
{"pattern": r"\beither\s+\w+\s+or\b", "keyword": "either...or", "description": "Explicitly disjunctive"},
],
}
CROSS_REF_PATTERNS = [
r"(?:Article|Art\.?)\s+\d+(?:\(\d+\))?(?:\([a-z]\))?",
r"(?:Section|Sec\.?|§)\s*\d+(?:\.\d+)?(?:\([a-z]\))?",
r"(?:Regulation|Directive)\s+\(?(?:EU|EC)\)?\s*(?:No\s*)?\d{4}/\d+",
r"(?:paragraph|para\.?)\s+\d+(?:\([a-z]\))?",
r"(?:Annex|Schedule|Appendix)\s+[IVXLCDM]+(?:\s+\w+)?",
r"(?:Chapter|Title|Part)\s+[IVXLCDM\d]+",
]
def extract_sentences(text: str) -> List[str]:
"""Split text into sentences, handling common legal abbreviations."""
# Protect common abbreviations from sentence splitting
protected = text
abbrevs = ["Art.", "Sec.", "No.", "para.", "e.g.", "i.e.", "et al.", "cf.", "v."]
for abbr in abbrevs:
protected = protected.replace(abbr, abbr.replace(".", "<DOT>"))
sentences = re.split(r'(?<=[.!?])\s+(?=[A-Z\d(])', protected)
return [s.replace("<DOT>", ".").strip() for s in sentences if s.strip()]
def find_keyword_matches(text: str) -> Dict[str, List[Dict[str, Any]]]:
"""Find all keyword matches in text, organized by classification."""
sentences = extract_sentences(text)
results: Dict[str, List[Dict[str, Any]]] = {}
for category, patterns in KEYWORD_PATTERNS.items():
matches = []
for pat_info in patterns:
pattern = re.compile(pat_info["pattern"], re.IGNORECASE)
for i, sentence in enumerate(sentences):
for match in pattern.finditer(sentence):
matches.append({
"keyword": pat_info["keyword"],
"description": pat_info["description"],
"sentence_index": i,
"sentence": sentence.strip(),
"position": match.start(),
"matched_text": match.group(),
})
if matches:
results[category] = matches
return results
def find_cross_references(text: str) -> List[Dict[str, str]]:
"""Extract all cross-references from text."""
refs = []
sentences = extract_sentences(text)
for i, sentence in enumerate(sentences):
for pattern in CROSS_REF_PATTERNS:
for match in re.finditer(pattern, sentence):
refs.append({
"reference": match.group(),
"sentence_index": i,
"context": sentence.strip(),
})
# Deduplicate by reference text
seen = set()
unique_refs = []
for ref in refs:
key = ref["reference"]
if key not in seen:
seen.add(key)
unique_refs.append(ref)
return unique_refs
def compute_statistics(matches: Dict[str, List], cross_refs: List, text: str) -> Dict[str, Any]:
"""Compute summary statistics for the analysis."""
sentences = extract_sentences(text)
total_keywords = sum(len(v) for v in matches.values())
keyword_counts: Dict[str, int] = {}
for category, items in matches.items():
for item in items:
kw = item["keyword"]
keyword_counts[kw] = keyword_counts.get(kw, 0) + 1
# Sort by frequency
sorted_keywords = sorted(keyword_counts.items(), key=lambda x: -x[1])
return {
"total_sentences": len(sentences),
"total_keywords_found": total_keywords,
"total_cross_references": len(cross_refs),
"keywords_by_category": {cat: len(items) for cat, items in matches.items()},
"keyword_frequency": dict(sorted_keywords[:20]),
"obligation_density": round(
matches.get("mandatory", []).__len__() / max(len(sentences), 1) * 100, 1
),
"exception_density": round(
matches.get("exception", []).__len__() / max(len(sentences), 1) * 100, 1
),
}
def build_obligation_map(matches: Dict[str, List]) -> List[Dict[str, str]]:
"""Build a deduplicated map of obligations from mandatory matches."""
obligations = []
seen = set()
for item in matches.get("mandatory", []):
key = item["sentence"]
if key not in seen:
seen.add(key)
obligations.append({
"type": "obligation",
"keyword": item["keyword"],
"text": item["sentence"],
})
for item in matches.get("prohibitive", []):
key = item["sentence"]
if key not in seen:
seen.add(key)
obligations.append({
"type": "prohibition",
"keyword": item["keyword"],
"text": item["sentence"],
})
return obligations
def build_exception_map(matches: Dict[str, List]) -> List[Dict[str, str]]:
"""Build a map of exceptions and conditions."""
exceptions = []
seen = set()
for item in matches.get("exception", []):
key = item["sentence"]
if key not in seen:
seen.add(key)
exceptions.append({
"type": "exception",
"keyword": item["keyword"],
"text": item["sentence"],
})
for item in matches.get("conditional", []):
key = item["sentence"]
if key not in seen:
seen.add(key)
exceptions.append({
"type": "condition",
"keyword": item["keyword"],
"text": item["sentence"],
})
return exceptions
def format_human_report(
matches: Dict[str, List],
cross_refs: List,
stats: Dict[str, Any],
obligations: List,
exceptions: List,
) -> str:
"""Format results as human-readable report."""
lines = []
lines.append("=" * 72)
lines.append("STATUTE KEYWORD ANALYSIS REPORT")
lines.append("=" * 72)
lines.append("\n--- SUMMARY ---")
lines.append(f"Total sentences analyzed: {stats['total_sentences']}")
lines.append(f"Total operative keywords found: {stats['total_keywords_found']}")
lines.append(f"Total cross-references found: {stats['total_cross_references']}")
lines.append(f"Obligation density: {stats['obligation_density']}% of sentences")
lines.append(f"Exception density: {stats['exception_density']}% of sentences")
lines.append("\n--- KEYWORD FREQUENCY ---")
for kw, count in stats.get("keyword_frequency", {}).items():
lines.append(f" {kw:25s} {count:4d}")
lines.append("\n--- KEYWORDS BY CATEGORY ---")
for cat, count in stats.get("keywords_by_category", {}).items():
lines.append(f" {cat:30s} {count:4d}")
lines.append(f"\n--- OBLIGATIONS ({len(obligations)}) ---")
for i, ob in enumerate(obligations, 1):
lines.append(f"\n [{i}] ({ob['type'].upper()}) [{ob['keyword']}]")
lines.append(f" {ob['text'][:200]}")
lines.append(f"\n--- EXCEPTIONS AND CONDITIONS ({len(exceptions)}) ---")
for i, ex in enumerate(exceptions, 1):
lines.append(f"\n [{i}] ({ex['type'].upper()}) [{ex['keyword']}]")
lines.append(f" {ex['text'][:200]}")
lines.append(f"\n--- CROSS-REFERENCES ({len(cross_refs)}) ---")
for ref in cross_refs:
lines.append(f" {ref['reference']}")
if matches.get("conjunctive_disjunctive"):
lines.append(f"\n--- AMBIGUITY FLAGS ({len(matches['conjunctive_disjunctive'])}) ---")
for item in matches["conjunctive_disjunctive"]:
lines.append(f" [{item['keyword']}] {item['sentence'][:150]}")
if matches.get("definition"):
lines.append(f"\n--- DEFINITIONS ({len(matches['definition'])}) ---")
for item in matches["definition"]:
lines.append(f" [{item['keyword']}] {item['sentence'][:150]}")
lines.append("\n" + "=" * 72)
return "\n".join(lines)
def main() -> None:
parser = argparse.ArgumentParser(
description="Analyze statute text for operative keywords and classify obligations."
)
parser.add_argument("--input", "-i", type=str, help="Path to statute text file")
parser.add_argument("--text", "-t", type=str, help="Inline statute text to analyze")
parser.add_argument("--output", "-o", type=str, help="Path to save output (JSON)")
parser.add_argument("--json", action="store_true", help="Output in JSON format")
args = parser.parse_args()
if not args.input and not args.text:
parser.print_help()
sys.exit(1)
try:
if args.input:
with open(args.input, "r", encoding="utf-8") as f:
text = f.read()
else:
text = args.text
if not text or not text.strip():
print("Error: Empty input text.", file=sys.stderr)
sys.exit(1)
matches = find_keyword_matches(text)
cross_refs = find_cross_references(text)
stats = compute_statistics(matches, cross_refs, text)
obligations = build_obligation_map(matches)
exceptions = build_exception_map(matches)
result = {
"statistics": stats,
"obligations": obligations,
"exceptions_and_conditions": exceptions,
"cross_references": cross_refs,
"definitions": [
{"keyword": m["keyword"], "text": m["sentence"]}
for m in matches.get("definition", [])
],
"ambiguity_flags": [
{"keyword": m["keyword"], "text": m["sentence"]}
for m in matches.get("conjunctive_disjunctive", [])
],
"overrides": [
{"keyword": m["keyword"], "text": m["sentence"]}
for m in matches.get("override", [])
],
}
if args.output:
with open(args.output, "w", encoding="utf-8") as f:
json.dump(result, f, indent=2, ensure_ascii=False)
print(f"Report saved to {args.output}")
elif args.json:
print(json.dumps(result, indent=2, ensure_ascii=False))
else:
print(format_human_report(matches, cross_refs, stats, obligations, exceptions))
except FileNotFoundError:
print(f"Error: File not found: {args.input}", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()
Related skills
FAQ
Does this give legal advice?
No. It is marked experimental and for educational and informational purposes only, and users should consult qualified legal professionals.
What do the tools do?
One scans statute text for operative keywords and classifies obligations; the other classifies requirements by type, team, enforcement and penalty.