Skip to content

PRD - JBRK Legal OS Reporting Letter (solution on DocGen)

status: draft
date: 2026-06-06
solution: jbrk
consumes: docgen framework
release: releases/r2-framework-production-features
primary-source: ../../reference/JBRK_Legal_OS_Info_Guide.docx

What this is. A solution-level PRD for one document type — JBRK Legal OS's tax-reorganization reporting letter — expressed entirely as a configuration of the generic DocGen framework. The goal is a genericity proof: show that DocGen's R2 composition primitives (Text / Snippet / Risk Block / Field + templated render + version history + generation snapshot) can produce this real, regulated document, and flag anything that does not fit a primitive. Vocabulary throughout is DocGen's; JBRK's origin term is noted once where it first appears.

Primary source: ../../reference/JBRK_Legal_OS_Info_Guide.docx (Richard Kirby for Jon Gilbert, 2026-04-21). Framework references: ../../reference/domain-model.md ([D-11]/[D-12]/[D-15]), ../../releases/r2-framework-production-features/r2-prd.md ([P2-composition]), ../../explanation/phoenix-uc2-analysis.md (gaps G1/G2/G3).


TL;DR [JB-tldr]

JBRK Legal OS is a real, working ~3,000-line engine that assembles Canadian tax-reorganization reporting letters from a structured fact graph using pre-written, lawyer-approved templates. Its governing principle: AI extracts facts; humans write legal analysis; the engine delivers it deterministically — every word in Sections II and III comes from templates the lawyers wrote and approved. No LLM ever drafts the body.

This PRD recasts that engine as a DocGen solution. The four JBRK layers map onto DocGen R2 primitives with no new vocabulary:

JBRK layer (origin term) DocGen primitive Role in the letter
Atom Text (structured: heading / narrative / bullets, Jinja, context-independent {% if %}) one transaction step → Section II
Molecule Snippet (ordered snippet_items of Texts + Risk Blocks, phase_order, entity_roles) a recognized transaction pattern
Risk Block Risk Block (approval-gated status draft→approved) one statutory risk → Section III
Variable Field (+ computed values via G2 = JBRK's tax_math) the flat dict the units interpolate

The output is one document with three Sections (I background facts, II transaction steps, III risk commentary), where II and III are assembled deterministically by collating units across all bound Snippets and numbering steps with a single running counter.

Bottom line (see TDD [JB-T-coverage]): every JBRK need maps to a DocGen primitive once R2's three forcing-function gaps land — G1 (structured/iterable render data), G2 (computed fields = tax_math), and the cross-snippet grouped-by-type assembly + step_num running counter ([T2-render]). The grouped assembly is real new render behavior, not just configuration; it is the one place JBRK forces framework work beyond "fill in the catalog." Flagged in [JB-T-misfits].


Use case [JB-feat-uc]

Who

  • Jon Gilbert — supervising tax lawyer at JBRK (Tomorrow Law Professional Corporation). Author of all legal content: the transaction-step Texts (Section II), the Risk Blocks (Section III), and the Snippet definitions that compose them. He owns the substance; Claude helps with template format.
  • Richard Kirby — infrastructure/plumbing: the fact-extraction adapter, the data graph, and the tax_math computations (→ DocGen computed Fields, G2). Reviews Jon's templates for render correctness.
  • The reviewing lawyer (Jon and/or Richard) — operates the human approval gate: signs off every Risk Block (status draft→approved) and reviews the assembled letter (Document.state) before any execution documents are generated.

What

A reporting letter — the analytical core of every tax-reorg file:

Section Content Produced by
Section I Background facts (entities, shareholdings, asset FMVs, the transaction context) facts gathered into the Field dict; narrative is templated or a tightly-scoped LLM summary of approved facts
Section II Transaction steps + tax consequences — every step across all transaction patterns, in execution order, sequentially numbered deterministic: all Text units across all bound Snippets, grouped, Jinja-rendered against Fields
Section III Strategic risk commentary — every statutory-risk analysis across all patterns deterministic: all approved Risk Block units across all bound Snippets, grouped

Transaction patterns (the Snippets we ship first)

The engine handles three patterns today and is designed to scale to ~15. The reporting letter for a file binds one or more of these (a real reorg is often a freeze then a pipeline):

Pattern (JBRK molecule) DocGen Snippet key Typical phase_order Composition (Texts → Risk Blocks)
Post-mortem pipeline post_mortem_pipeline 10 Incorporate Newco + s.85(1) Transfer + Tax-Funding Dividend + Surplus Extraction → s.84(1), s.84(2), s.55(2)/Part IV, s.164(6), GAAR
Inter vivos pipeline inter_vivos_pipeline 10 similar step chain, living transferor → overlapping risk set
Estate freeze estate_freeze 0 freeze exchange + Newco subscribe + (optional) crystallization → s.86, s.85, valuation/GAAR risks

phase_order sorts the patterns when several apply to one letter (freeze 0 → crystallization 1 → pipeline 10), so Section II reads in execution order even across patterns.

The human approval gate (non-negotiable)

This is the reason the document exists in DocGen and not as free LLM prose. Two layers:

  1. Per-unit gate. A Risk Block renders in production only when status='approved' ([P2-feat-2]). Draft blocks are refused or rendered visibly tagged DRAFT. The lawyer authors a draft, reviews, and promotes it once — institutional knowledge captured as a reusable, approved unit.
  2. Document-level gate. The assembled letter sits at Document.state='under-review' for lawyer sign-off; only after sign-off (finalized) may downstream execution documents (T2057 elections, transfer agreements, resolutions) be generated. The gate is between assembly and execution — DocGen's render produces the letter; execution-doc generation is a separate, gated step.

Inputs [JB-feat-inputs]

The relational fact graph (ingestion is faked/mocked for this solution)

JBRK extracts an accountant's instruction-letter PDF into a relational graph. For this DocGen solution, ingestion is mocked — a fixture graph stands in for the extractor (the real PDF→graph extractor is JBRK solution code, not framework, and lands later). The graph shape:

  • Corporations — tax attributes: name, jurisdiction, fiscal year end, CCPC status, retained earnings, CDA / GRIP / NERDTOH / ERDTOH balances, total FMV, total PUC.
  • Individuals — roles (SHAREHOLDER, EXECUTOR, TRUSTEE, BENEFICIARY, DIRECTOR, SUCCESSOR), spouse_id, children_ids.
  • CorporateAssets — FMV, ACB, active-business-asset flag.
  • Shareholdings (edges) — share class, quantity, PUC, ACB, FMV, voting/participating/redeemable rights.
  • TransactionSteps (edges) — step_type (INCORPORATE, TRANSFER_SHARES, EXCHANGE_SHARES, PAY_DIVIDEND, …), entity refs, subject property, consideration, optional elected amount.

The Field dict (~60 values) and tax_math

An adapter walks the graph and flattens it to a Field dict the templates interpolate ({{ Opco_name }}, {{ Extraction_amount }}, {{ capital_gain }}, {{ accounting_firm }}, …). Some values are computed, not stored — capital gains, deemed dividends, safe-income figures — produced by JBRK's tax_math/ pure functions (one module per ITA provision, each unit-tested). In DocGen terms these are computed Fields (G2): solution-registered pure functions whose outputs merge into the render scope. The framework owns the merge plumbing; JBRK owns the formulas.

"Every word approved" governance

Facts may be AI-extracted (Section I inputs). Analysis is never AI-authored. Every Text and every Risk Block is lawyer-written, reviewed, and (for Risk Blocks) explicitly approved before it can appear in a produced letter. The approval gate + version history + generation snapshot together make this enforceable and auditable, not aspirational.

Multi-Snippet (phase-ordered) documents

One letter can bind multiple Snippets (e.g. an estate freeze followed by a post-mortem pipeline). document_snippets binds each pattern to the document and maps roles (opco, transferor, …) to concrete graph entities for this file (entity_bindings_json). Assembly orders all units by (phase_order, ordinal).


Success criteria [JB-feat-success]

# Criterion How verified
[JB-success-1] Deterministic II/III from approved units only. Re-rendering the same document from the same approved units + Field values yields byte-identical Section II and III. No LLM in the II/III path. re-render check; generation snapshot reproduces byte-for-byte (templated path)
[JB-success-2] Correct multi-Snippet assembly + sequential step numbering. Binding freeze (phase_order=0) + pipeline (phase_order=10) yields Section II with all steps in (phase_order, ordinal) order, numbered 1..N by a single running counter across both patterns; Section III lists all approved Risk Blocks in the same order. worked example ([JB-T-example]); assert step_num runs 1..N across snippets, not per-snippet
[JB-success-3] Per-unit approval enforced. A Risk Block with status='draft' does not appear in a finalized letter (refused or DRAFT-tagged). render with a draft block present → assert excluded/tagged
[JB-success-4] Lawyer sign-off workflow. The letter cannot drive execution-document generation until Document.state='finalized'; the audit spine (version history + generation snapshot) can answer "show me the exact approved units + facts that produced the letter we filed." state-gate check; generation-snapshot manifest pins every consumed unit version
[JB-success-5] Context-independent Texts. The same s85_transfer Text renders correctly in a pipeline and a freeze, with variants driven only by {% if %} against the Field dict — never hardcoded. render s85_transfer under two Snippets; diff is conditional-driven only
[JB-success-6] Scales additively. Adding a 4th transaction pattern (e.g. s.87 amalgamation) is "author Texts + Risk Blocks + one Snippet definition" — no framework change. add a fixture Snippet; no engine edits

Out of scope (this solution, this release)

  • Real PDF→graph ingestion / extraction prompts — JBRK solution code, mocked here.
  • Execution documents (T2057, transfer agreements, resolutions) and closing books — downstream of the gate; future.
  • Error-detection rules that catch accountant mistakes in instruction letters — JBRK solution logic; overlaps DocGen's verify/precondition (G3) but not built here.

Cross-references

  • TDD (the configuration + genericity proof): ./tdd.md
  • Primary source: ../../reference/JBRK_Legal_OS_Info_Guide.docx
  • DocGen R2 PRD: ../../releases/r2-framework-production-features/r2-prd.md ([P2-composition])
  • DocGen R2 TDD: ../../releases/r2-framework-production-features/r2-tdd.md ([T2-render] assembly modes)
  • DocGen domain model: ../../reference/domain-model.md ([D-11], [D-12] walkthroughs 3+4, [D-15] Fields)
  • Gap analysis: ../../explanation/phoenix-uc2-analysis.md (G1/G2/G3)