Classifies the treatment of Competition Compliance Programmes (CCPs) in competition law enforcement documents.
Library skill — the default version is maintained in GitHub; edits you make live in your own clone.
Structured workflow for classifying how Competition Compliance Programmes (CCPs) are treated in competition enforcement documents (policy documents and cases/judgments).
When the user provides a PDF file path:
Run the following Python snippet via Bash to extract text:
python
import fitz, sys
doc = fitz.open(sys.argv[1])
md = "\n\n".join(page.get_text("text") for page in doc)
with open("_tmp_converted.md", "w", encoding="utf-8") as f:
f.write(md)
print("Converted successfully.")
Example: python3 -c "..." path/to/document.pdf
Read _tmp_converted.md to confirm content loaded correctly.
Inform user: "PDF converted. Beginning analysis..."
_tmp_converted.md._tmp_converted.md with the translated content.Read the entire converted markdown. Do not skim — classification must be based on a full understanding of the document.
3a. Extract document metadata (needed for Excel if a new row must be created):
- Name of Document (Col A): PDF basename without extension (e.g., Case_EU_1)
- Country / Authority (Col B): the jurisdiction or authority the document relates to (e.g., EU, UK, France, Canada Competition Bureau)
- Document Type (Col C): one of Policy Document, Case, Judgment, Decision, Guidelines, or similar
- Title (Col D): the official title of the document as found in its header/cover
- Date (Col E): the date of publication, decision, or last modification as stated in the document; if not found, use the PDF file's modification date
3b. Identify CCP-relevant content: Identify all paragraphs that mention any of the following (and variations): - compliance programme / compliance program - compliance system / compliance framework - compliance measures / compliance culture - internal compliance / corporate compliance
Critical rule for cases and judgments: The document may contain arguments made by the parties (company, authority, opposing counsel). These arguments do NOT determine the classification. Only the court's or authority's own decision, ruling, or finding is what counts.
Consult assets/examples.md for calibration on edge cases. Note whether CCP treatment is explicit or only implied.
Assign one of the following categories based on the authority's/court's treatment.
Every classification MUST be tagged with one of the following confidence bands. Record the band in the scratchpad and surface it in the Phase 6 summary so a downstream researcher can triage which rows need re-review without re-reading each document.
| Band | When to apply |
|---|---|
| High | Explicit ruling/decision language from the authority or court directly stating how the CCP is treated; multiple corroborating passages; no translation step or translation is from a closely related language with stable terminology. |
| Medium | Authority/court treatment is clear from context but not stated in a single explicit sentence; reasoning required to bridge passages; or High-quality classification that depends on a translation from a non-English source. |
| Low | Single ambiguous paragraph; treatment inferred from indirect language; translation fidelity uncertain; mixed signals across passages. Low confidence rows are candidates for unsure and must be re-reviewed before any downstream use. |
If you cannot honestly justify at least Medium, prefer the unsure category over forcing a primary label.
| Category | When to use |
|---|---|
as an offence |
CCP existence treated as aggravating factor — CCP deemed a façade, ineffective, or its violation increases penalty |
as a defence (allowed) |
CCP raised as mitigating factor AND the authority/court accepted it, reducing the fine/penalty — cases/judgments only |
as a defence (rejected) |
CCP raised as mitigating factor BUT the authority/court rejected it — cases/judgments only |
as a defence |
CCP treated as a mitigating factor; outcome not further distinguished — policy documents only |
as a remedy |
CCP imposed or mandated as a corrective/remedial measure (e.g., condition of settlement) |
as offence and remedy |
Both offence and remedy roles present in the same document |
as defence and remedy |
Both defence and remedy roles present in the same document |
irrelevant |
CCP mentioned but not treated under any enforcement role (e.g., merely referenced in passing) |
unsure |
CCP referenced but how it was treated is genuinely ambiguous — state reason clearly |
neutral |
Authority acknowledges CCP existence but neither accepts nor rejects it as relevant to the outcome |
Document type rule:
- Case or judgment → use as a defence (allowed) or as a defence (rejected) sub-categories
- Policy document by a competition authority → use plain as a defence
If uncertain: do not guess. Use unsure and explain why.
Case_EU_1.pdf → Output: scratchpad_Case_EU_1.mdassets/ScratchpadTemplate.md._tmp_converted.md.Report to the user:
Scratchpad saved: scratchpad_[name].md
Classification summary:
- Category: [category]
- Explanation: [one sentence]
- Reference: "[excerpt...]"
Proceed to update Output.xlsx? (yes/no)
Wait for explicit user confirmation before proceeding.
Output.xlsx in the current working directory.If a matching row is found:
- Fill in only:
- Column F (Category)
- Column G (Explanation/Note)
- Column H (Reference)
- Save and report: "Updated existing row for [document name] in sheet [sheet name]."
If no matching row is found:
- Determine the correct sheet:
- Document type is Policy Document / Guidelines / Agency publication → AgencyDoc sheet
- Document type is Case / Judgment / Decision → the sheet matching the country (e.g., UK, EU, France, Canada, USA, Sweden, Italy, Spain)
- Halt on novel jurisdiction: if the country/authority does NOT match any of the nine listed sheets, STOP. Do NOT silently fall back to AgencyDoc. Report to the user:
> "Novel jurisdiction detected: [country/authority]. The configured sheets are: AgencyDoc, UK, Canada, USA, EU, France, Sweden, Italy, Spain. Output.xlsx will NOT be modified until you confirm one of the following: (a) route to AgencyDoc with a novel-jurisdiction flag in Column G; (b) add a new sheet for this jurisdiction and re-run; (c) abort this classification."
Wait for explicit user direction. Under no circumstances append the row before the user has chosen.
- Append a new row at the bottom of the correct sheet, filling in all columns:
- Column A (Name of Document): PDF basename without extension
- Column B (Country / Authority): extracted in Phase 3a
- Column C (Document Type): extracted in Phase 3a
- Column D (Title): extracted in Phase 3a
- Column E (Date): extracted in Phase 3a
- Column F (Category): the assigned category
- Column G (Explanation/Note): the one-sentence explanation
- Column H (Reference): the verbatim reference paragraph(s)
- Save and report: "No existing row found — created new row for [document name] in sheet [sheet name]."
Use openpyxl via Bash to perform the read and write. When appending, use ws.append([...]) to add the new row after the last populated row.
assets/examples.md — Annotated classification examples for calibrationassets/ScratchpadTemplate.md — Template for scratchpad output filesThis skill was imported from Leona Zhang's MIT-licensed GitHub release and evaluated against the Legal Skill Design Framework on 2026-05-11. The original technical content (PDF→Markdown conversion, taxonomy, scratchpad workflow, Excel update logic) is preserved unchanged. The following targeted additions were made under a "SOME CONCERN" verdict:
unsure rather than being forced into a primary label. This addresses the QA finding that the original unsure/neutral labels did not operationalise certainty against the primary classification.AgencyDoc sheet whenever a country/authority did not match one of the nine configured sheets. That silent fall-through could quietly corrupt Output.xlsx by routing (for example) a Japanese or Australian decision into the agency-document bucket. The remediated behaviour halts before any write, surfaces the novel jurisdiction explicitly, and requires the user to choose between flagged routing, adding a new sheet, or aborting.version: 1.0.0, last_reviewed: 2026-05, and last_reviewed_by: LegalQuants (QA remediation) added alongside the original author: and license attribution. Leona's authorship and the MIT LICENSE are preserved as required.Remaining QA observations not addressed in this pass (audience block, scope-boundary section, "limits / not legal advice" block, moving inline Python into scripts/, surfacing the PDF-date fallback in the scratchpad, halt-on-translation-confidence trigger) are flagged in /tmp/qa-results/classify-ccp.md for a future review cycle.