AI Skill Report Card
Generating OTC Trade Confirmations
Quick Start13 / 15
Pythonfrom confirmation_pipeline import generate_confirmation result = generate_confirmation( qgml_file="trade_12345.qgml", template_rules="irs_confirmation_rules.json", output_dir="./confirmations/trade_12345/" ) # result.word_doc -> v1 .docx generated by LLM from QGML + rules # result.version -> 1 # After user edits in Word and re-uploads: new_version = register_edit(result.word_doc_id, edited_file="trade_12345_edited.docx") # new_version.version -> 2, diff stored, PDF regenerated pdf_path = render_pdf(new_version.word_doc_id)
Recommendation▾
Add a concrete QGML input snippet to ground the parsing step in real syntax rather than abstract description
Workflow14 / 15
Progress:
- [ ] Step 1: Parse and validate QGML trade data
- [ ] Step 2: Load template rules (JSON) matching trade type
- [ ] Step 3: Generate Word doc v1 via LLM (QGML + rules -> prose/clauses)
- [ ] Step 4: Store v1 as baseline with metadata (trade ID, timestamp, checksum)
- [ ] Step 5: User edits Word doc (manual review/negotiation changes)
- [ ] Step 6: Ingest edited doc, diff against last version, create vN
- [ ] Step 7: Validate edits don't break required FpML-mapped fields
- [ ] Step 8: Convert final approved version to PDF
- [ ] Step 9: Archive full version history + audit trail
Step 1: QGML Parsing & Validation
- Parse QGML into a structured trade object (parties, notional, rates, dates, product type).
- Validate against schema before generation — malformed QGML must fail fast, never reach the LLM.
- Map QGML elements to template placeholder keys (e.g.,
tradeDate,fixedRate,counterparty1).
Step 2: Template Rules (JSON)
Rules JSON defines structure per product type, not prose:
JSON{ "productType": "InterestRateSwap", "sections": [ {"id": "header", "required": true, "fields": ["tradeDate", "tradeId", "parties"]}, {"id": "economic_terms", "required": true, "fields": ["notional", "fixedRate", "floatingIndex"]}, {"id": "governing_law", "required": true, "static": true, "text_key": "isda_master_2002"} ], "conditional_sections": [ {"if": "hasCollateral", "section": "credit_support_annex"} ], "llm_instructions": "Use formal ISDA confirmation language. Do not invent terms not present in QGML." }
- Keep
static(boilerplate/legal) sections literal — never LLM-generated — to avoid hallucinated legal language. - Only dynamic economic terms go through the LLM, populated strictly from parsed QGML fields.
Step 3: LLM Word Doc Generation
- Prompt = QGML-derived field map + matching rule section + instruction to only use provided values.
- Generate as structured content (python-docx or docx template merge), not freeform LLM-authored formatting, to keep layout consistent across versions.
- Tag every generated field in the doc with a hidden bookmark/content-control ID (
fld_fixedRate) so later diffs can map back to source data, not just text position.
Step 4 & 6: Versioning
- Each save = immutable version:
{version_id, parent_version_id, docx_blob, created_by, timestamp, change_summary}. - Compute diff using python-docx XML or a doc-diff library; store as structured diff (field-level where possible, paragraph-level fallback) alongside the full blob.
- Never overwrite — version N+1 always references N as parent, forming a linear (or branchable) history.
- Track
edited_byasllmfor v1,user:<id>for subsequent human edits.
Step 7: Validation Gate
Before allowing PDF generation, verify:
- All
requiredsections from rules JSON still present. - Economic terms (notional, rate, dates) are internally consistent (e.g., not blank, not contradicting QGML source unless flagged as an intentional amendment).
- Flag (don't block) edits that change economically material terms — route for compliance review.
Step 8: PDF Rendering
- Convert final docx version to PDF (LibreOffice headless or docx2pdf) preserving tracked-changes-accepted state.
- Embed version metadata in PDF properties/footer (e.g., "Confirmation v3 — generated 2024-06-01").
Recommendation▾
Include an example of a rejected/failing validation case (e.g., malformed QGML or missing required field) to show error-handling behavior
Examples16 / 20
Example 1:
Input: QGML for a vanilla IRS trade, rules JSON for InterestRateSwap.
Output: v1 .docx with header/parties/economic terms auto-filled, ISDA boilerplate inserted verbatim, saved as version 1, status draft.
Example 2:
Input: User changes fixed rate from 3.25% to 3.30% in Word and re-uploads.
Output: version 2 created, diff shows fixedRate: 3.25% -> 3.30%, flagged as material economic change for review, PDF not generated until approved.
Example 3: Input: User only fixes a typo in a party's address. Output: version 2 created, diff shows non-material text change, auto-approved, PDF regenerated immediately.
Recommendation▾
Show a brief sample of the actual diff output format (e.g., JSON structure) referenced in Step 6 and Example 2
Best Practices
- Separate structure (JSON rules) from content generation (LLM) from legal boilerplate (static text) — never let the LLM author binding legal language.
- Use content controls/bookmarks in docx, not plain text matching, to reliably trace fields across edits and versions.
- Keep every version immutable and append-only; version history is itself an audit artifact for disputes.
- Validate QGML against schema before any generation step — garbage in, garbage confirmation out.
- Distinguish material (economic terms) vs. non-material (formatting, typos) diffs and route accordingly.
Common Pitfalls
- Letting the LLM freely generate legal/boilerplate clauses — causes inconsistent or incorrect legal language across trades.
- Diffing only at the raw-text level — misses which specific trade field changed, breaking traceability back to QGML.
- Overwriting prior versions instead of appending — destroys audit trail required for trade dispute resolution.
- Generating PDF before validating required sections/fields are intact post-edit.
- Not tagging LLM-generated fields distinctly from user-edited fields, making it impossible to tell what a human changed vs. what came from source data.