"""Generate a realistic demo Master Services Agreement PDF. Deliberately seeded with the risk patterns the engine detects: uncapped liability, 90-day auto-renewal notice, one-sided termination, slow breach notification, exclusivity, high late-payment interest, sole-remedy SLA credits — so the demo tells the full story end-to-end. .venv/bin/python backend/scripts/make_demo_contract.py """ from __future__ import annotations import pathlib from reportlab.lib.pagesizes import A4 from reportlab.pdfbase.pdfmetrics import stringWidth from reportlab.pdfgen import canvas OUT = pathlib.Path(__file__).resolve().parents[2] / "data" / "samples" / "demo_msa.pdf" PARAS = [ ("T", "MASTER SERVICES AGREEMENT"), ("P", 'This Master Services Agreement (the "Agreement") is entered into as of ' 'July 1, 2026 (the "Effective Date") by and between Acme Industries Inc ' '("Client"), a Delaware corporation with offices at 100 Market Street, ' 'San Francisco, CA, and Globex Services Ltd ("Supplier"), a company ' 'registered in England and Wales with offices at 1 Canary Wharf, London. ' 'Client and Supplier are each a "Party" and together the "Parties".'), ("H", "1. Definitions"), ("P", '"Confidential Information" means all non-public information disclosed by ' 'one Party to the other, whether oral or written, that is designated as ' 'confidential or that reasonably should be understood to be confidential. ' '"Deliverables" means the work product described in a Statement of Work. ' '"Services" means the managed analytics platform services described in ' 'Exhibit A. "Fees" means the charges set out in Section 4.'), ("H", "2. Services and Deliverables"), ("P", "Supplier shall provide the Services to Client in accordance with this " "Agreement and each Statement of Work. Supplier shall deliver the initial " "implementation plan to Client no later than August 15, 2026. Supplier " "shall conduct quarterly business reviews with Client, the first such " "review to occur by October 30, 2026. Client shall provide Supplier with " "timely access to systems and personnel reasonably required to perform " "the Services."), ("H", "3. Exclusivity"), ("P", "During the Term, Client shall procure all managed analytics services " "exclusively from Supplier and shall not engage any third party to " "provide services that are substantially similar to the Services without " "Supplier's prior written consent."), ("H", "4. Fees and Payment"), ("P", "Client shall pay all undisputed Fees within sixty (60) days of receipt " "of a valid invoice (Net 60). Late payments shall accrue interest at 2% " "per month or the maximum rate permitted by law, whichever is lower. " "Supplier may increase the Fees by no more than 5% per year upon ninety " "(90) days' written notice. All Fees are exclusive of applicable taxes, " "which Client shall pay."), ("H", "5. Term and Renewal"), ("P", "This Agreement shall commence on the Effective Date and continue for an " "initial term of three (3) years, expiring on June 30, 2029 (the " '"Initial Term"). Thereafter this Agreement shall automatically renew ' "for successive twelve (12) month renewal terms unless either Party " "gives written notice of non-renewal at least ninety (90) days prior to " "the end of the then-current term."), ("H", "6. Termination"), ("P", "Supplier may terminate this Agreement for convenience upon sixty (60) " "days' written notice to Client. Either Party may terminate this " "Agreement upon thirty (30) days' written notice if the other Party " "materially breaches this Agreement and fails to cure such breach within " "the notice period. Upon termination, Client shall pay all Fees accrued " "through the effective date of termination."), ("H", "7. Service Levels"), ("P", "Supplier shall make the Services available 98.5% of the time in each " "calendar month, excluding scheduled maintenance. If availability falls " "below the foregoing commitment, Client shall be entitled to service " "credits as set out in Exhibit B, which credits shall be Client's sole " "and exclusive remedy for any failure to meet the service levels."), ("H", "8. Confidentiality"), ("P", "Each Party shall protect the other Party's Confidential Information " "using at least the same degree of care it uses for its own confidential " "information, and in no event less than reasonable care. This Section 8 " "shall survive termination of this Agreement for a period of five (5) " "years. Each Party shall promptly notify the other upon becoming aware " "of any unauthorized disclosure of Confidential Information."), ("H", "9. Data Protection"), ("P", "Supplier shall process Client personal data only on Client's documented " "instructions and in compliance with applicable data protection laws, " "including GDPR where applicable. Supplier shall notify Client of any " "security breach affecting Client personal data within seven (7) days of " "becoming aware of such breach. Supplier shall implement appropriate " "technical and organizational measures as described in Section 9 and " "Exhibit C."), ("H", "10. Indemnification"), ("P", "Supplier shall indemnify, defend and hold harmless Client from and " "against any and all claims, losses, liabilities and expenses arising " "out of or relating to the Services, except to the extent caused by " "Client's gross negligence. Client shall promptly notify Supplier of any " "claim subject to indemnification under this Section 10."), ("H", "11. Limitation of Liability"), ("P", "EXCEPT FOR A PARTY'S INDEMNIFICATION OBLIGATIONS, IN NO EVENT SHALL " "EITHER PARTY BE LIABLE FOR ANY INDIRECT, INCIDENTAL OR CONSEQUENTIAL " "DAMAGES. THE PARTIES AGREE THAT SUPPLIER'S LIABILITY FOR DIRECT DAMAGES " "SHALL NOT BE LIMITED AND NOTHING IN THIS AGREEMENT SHALL LIMIT " "SUPPLIER'S ABILITY TO RECOVER ALL AMOUNTS DUE."), ("H", "12. Insurance"), ("P", "Supplier shall maintain commercial general liability insurance with " "policy limits of not less than $2,000,000 per occurrence and shall " "provide certificates of insurance to Client upon request."), ("H", "13. Audit Rights"), ("P", "Client may, upon thirty (30) days' written notice and not more than " "once per year, audit Supplier's books and records solely as they relate " "to the Fees charged under this Agreement."), ("H", "14. Assignment"), ("P", "Neither Party may assign this Agreement without the prior written " "consent of the other Party, except that Supplier may assign this " "Agreement to an affiliate or in connection with a merger or sale of " "substantially all of its assets without consent."), ("H", "15. Governing Law"), ("P", "This Agreement shall be governed by the laws of England and Wales, and " "the Parties submit to the exclusive jurisdiction of the courts of " "London, England, subject to the dispute escalation process described " "in Section 15."), ("H", "16. Notices"), ("P", "All notices under this Agreement shall be in writing and delivered to " "the addresses set out above, and shall be deemed given upon receipt. " "Notices of non-renewal under Section 5 and termination under Section 6 " "must be sent by registered mail."), ] MARGIN = 56 WIDTH, HEIGHT = A4 # 595 x 842 points LINE_H = {"T": 22, "H": 16, "P": 13} FONT = {"T": ("Helvetica-Bold", 16), "H": ("Helvetica-Bold", 11.5), "P": ("Helvetica", 10)} GAP = {"T": 20, "H": 6, "P": 12} def wrap(text: str, fontname: str, size: float, width: float) -> list[str]: words = text.split() lines, cur = [], "" for w in words: trial = (cur + " " + w).strip() if stringWidth(trial, fontname, size) <= width: cur = trial else: if cur: lines.append(cur) cur = w if cur: lines.append(cur) return lines def main() -> None: OUT.parent.mkdir(parents=True, exist_ok=True) c = canvas.Canvas(str(OUT), pagesize=A4) pages = 1 y = MARGIN + 10 # measured from the TOP; reportlab draws from the bottom usable = WIDTH - 2 * MARGIN for kind, text in PARAS: fname, fsize = FONT[kind] lines = wrap(text, fname, fsize, usable) needed = len(lines) * LINE_H[kind] + GAP[kind] if y + needed > HEIGHT - MARGIN and kind != "T": c.showPage() pages += 1 y = MARGIN + 10 c.setFont(fname, fsize) for line in lines: c.drawString(MARGIN, HEIGHT - y, line) y += LINE_H[kind] y += GAP[kind] c.save() print(f"wrote {OUT} ({pages} pages)") if __name__ == "__main__": main()