Legal intake software

CaseSpark

File Faster, Bill More

CaseSpark automates legal client intake, instant conflict screening, and jurisdiction-aware document assembly for solo attorneys and two-attorney family-law practices, converting calls into e-sign-ready filings in minutes while guiding customizable intake workflows, preventing missed conflicts, cutting intake time up to 70%, and recovering billable hours so matters move from call to filing fast.

Subscribe to get amazing product ideas like this one delivered daily to your inbox!

CaseSpark

Product Details

Explore this AI-generated product idea in detail. Each aspect has been thoughtfully created to inspire your next venture.

Vision & Mission

Vision
Empower solo attorneys to transform intake into flawless, jurisdiction-compliant filings in minutes, reclaiming billable hours and peace of mind.
Long Term Goal
Within 5 years, enable 25,000 solo attorneys to reduce intake time by 60% and prevent 95% of conflict oversights, converting calls into filed, compliant matters within minutes.
Impact
CaseSpark reduces client intake time by up to 70% for solo attorneys and two-attorney family-law practices, eliminates 95% of conflict oversights, and recovers 3–6 billable hours per attorney weekly—moving matters from call to filed, compliant documents in minutes.

Problem & Solution

Problem Statement
Solo attorneys and two-attorney family-law practices lose billable hours to manual client intake, missed conflict checks, and repetitive document drafting because existing intake tools are bloated, hard to configure, and lack jurisdiction-aware templates.
Solution Overview
CaseSpark converts each client call into a compliant matter by guiding attorneys through a customizable intake wizard with instant conflict screening and one-click, jurisdiction-aware document assembly that produces e-sign-ready filings in minutes.

Details & Audience

Description
CaseSpark automates legal client intake, conflict checks, and document generation with guided workflows and e-sign-ready forms. It serves solo attorneys and very small law firms who need faster, compliant onboarding. It cuts intake time, prevents missed conflicts, and recovers billable hours so matters move from call to filing in minutes. Jurisdiction-aware, editable clause snippets instantly assemble filings tailored to local rules.
Target Audience
Solo attorneys (30–60) in small firms seeking faster, compliant onboarding who prefer simple workflows
Inspiration
I watched a solo family‑law attorney under lamplight retype client details from a crumpled intake form, coffee cooling beside a stack of pleadings. An avoidable conflict surfaced a week later that nearly derailed the case. Seeing sticky notes, missed checks, and endless clause edits revealed the solution: a guided intake that screens conflicts instantly and inserts jurisdiction‑smart clauses so calls become filed matters in minutes.

User Personas

Detailed profiles of the target users who would benefit most from this product.

B

Bilingual Bridge Bianca

- Solo family-law attorney; 8 years in practice in Houston/San Antonio. - Serves 60% Spanish-speaking households; first-gen professional. - JD from South Texas College of Law; bilingual staff of one. - Annual revenue $220K–$360K; mobile-first, iPhone and cloud tools.

Background

Grew up translating for relatives during custody disputes, seeing errors snowball. Lost early leads to English-only forms; vowed to make bilingual intake effortless and immediate.

Needs & Pain Points

Needs

1. Seamless bilingual scripts, fields, and documents. 2. SMS-first e-sign with read receipts. 3. Auto-detect language per contact and matter.

Pain Points

1. Leads drop when forms are English-only. 2. Email-only packets go unopened for days. 3. Family members share names, confusing conflicts.

Psychographics

- Language access equals dignity and retention. - Clarity beats legalese every single time. - Trust is built via rapid, respectful replies. - Progress measured by signed, accurate packets.

Channels

1. WhatsApp (client updates) 2. Google Business Messages (intake chats) 3. LinkedIn (peer tips) 4. Facebook Groups (local community) 5. State Bar Listserv (practice guidance)

M

Migration Maestro Maya

- Two-attorney family firm’s de facto tech lead and paralegal. - 9 years experience; based in Phoenix metro. - Migrating 3,200 contacts and 1,100 matters from legacy tools. - Budget owner for software transitions; vendor-savvy and deadline-driven.

Background

Previously suffered a botched CRM import that broke conflicts and contacts. Built checklists and scripts to prevent duplicates, gaps, and downtime during any migration.

Needs & Pain Points

Needs

1. Zero-loss import with relationship preservation. 2. Flexible field mapping to templates. 3. Rollback, logs, and sandbox testing.

Pain Points

1. Duplicates corrupt conflict screening accuracy. 2. CSV imports break linked parties. 3. Downtime stalls revenue-generating intakes.

Psychographics

- Clean data or nothing ships. - Trust earned through transparent, testable steps. - Documentation today prevents chaos tomorrow. - Efficiency without sacrificing accuracy.

Channels

1. LinkedIn (migration case studies) 2. Clio Community (peer threads) 3. Legaltech Newsletters (tool updates) 4. G2 (vendor reviews) 5. State Bar CLE (PM sessions)

M

Mobile-First Marco

- Solo family attorney; 5 years licensed; Chicagoland circuit. - iPhone-centric; MacBook secondary; CarPlay calls between stops. - 70% new leads via phone calls and texts. - Revenue $180K–$300K; minimal staff support.

Background

Lost emergency orders due to dead laptop and captive Wi‑Fi. Rebuilt his day around mobile capture, text follow-ups, and filing within hours.

Needs & Pain Points

Needs

1. One-hand intake and texting e-sign. 2. Offline capture with auto-sync. 3. Tap-to-run conflict checks.

Pain Points

1. Spotty courthouse Wi‑Fi kills sessions. 2. Clients ignore email-only packets. 3. Laptop boot delays lose momentum.

Psychographics

- Speed is service; slow is lost trust. - Mobile-first over desktop convenience. - Notifications drive action and outcomes. - Simple beats perfect under pressure.

Channels

1. LinkedIn (practice hacks) 2. YouTube (short tutorials) 3. Apple Podcasts (commute learning) 4. Reddit r/LawFirm (tool opinions) 5. State Bar App (CLE updates)

R

Referral Rainmaker Riya

- Two-attorney suburban practice; Riya co-manages marketing and intake. - 11 years practicing family law; Northern New Jersey. - 55% matters originate from professional referrals. - Tracks budgets, conversion, and time-to-consult weekly.

Background

Built a referral web with counselors and mediators after early droughts. Missed callbacks once cost a flagship referrer; now she automates handoffs and updates.

Needs & Pain Points

Needs

1. Source tracking from first call to filing. 2. Referral-specific scripts and follow-ups. 3. Automated referrer status updates.

Pain Points

1. Leads leak between receptionist and consult. 2. Unknown ROI across referral partners. 3. Referrer updates slip through cracks.

Psychographics

- Relationships compound when nurtured systematically. - Data cuts through optimistic guessing. - Reciprocity matters: update referrers promptly. - Consistency beats sporadic heroics.

Channels

1. LinkedIn (partner outreach) 2. Google Ads (lead capture) 3. Facebook Groups (therapist communities) 4. Mailchimp (referrer newsletters) 5. State Bar Events (networking)

M

Mediator-Minded Miles

- Solo attorney-mediator; 10 years in practice; Denver area. - 70% mediation, 30% limited-scope filings. - Works from shared suite; minimal admin support. - Moderate fees; volume-driven calendar.

Background

Left litigation after burnout and hostile hearings. Designed a calm, parallel intake that respects both parties and speeds consensus.

Needs & Pain Points

Needs

1. Mirrored two-party intake questionnaires. 2. Dual-side conflict checks with relatives. 3. Neutral, mediation-focused document sets.

Pain Points

1. One-sided templates alienate participants. 2. Re-entering data for spouse two. 3. Adversarial phrasing derails sessions.

Psychographics

- Neutral tone builds trust and momentum. - Symmetry for both parties reduces friction. - Preparation prevents flare-ups at signing. - Empathy paired with procedural rigor.

Channels

1. Mediate.com (best practices) 2. LinkedIn (ADR peers) 3. State Bar ADR (resources) 4. Calendly (scheduling marketplace) 5. YouTube (workflow demos)

P

Privacy-First Priya

- Two-attorney boutique; Los Angeles; high-profile clientele. - 8 years licensed; prior in-house privacy counsel. - Mac-first, encrypted devices; private office suite. - Premium pricing; low-volume, high-touch matters.

Background

Saw a prior firm embarrassed by a forwarded attachment. Adopted strict access controls and redaction across every intake and document pipeline.

Needs & Pain Points

Needs

1. Field-level permissions with roles. 2. Masked PII in forms and exports. 3. Expiring, watermarked share links.

Pain Points

1. Assistants see unnecessary sensitive details. 2. Email attachments get forwarded accidentally. 3. Vendors vague about encryption specifics.

Psychographics

- Trust is earned through verifiable controls. - Default-deny beats hopeful oversight. - Transparency via logs reduces anxiety. - Paying more beats risking exposure.

Channels

1. LinkedIn (security updates) 2. IAPP (privacy guidance) 3. CISA Alerts (threat awareness) 4. Legal Tech News (vendor scrutiny) 5. G2 (security reviews)

Product Features

Key capabilities that make this product valuable to its target users.

TrustSafe Routing

Automatically routes retainers to IOLTA/trust and flat fees to operating accounts with built‑in guardrails that prevent commingling. Per‑matter account mapping, instant trust ledgers, and real‑time compliance alerts keep solo and small firms audit‑ready without extra bookkeeping.

Requirements

Per-Matter Account Mapping
"As a solo attorney, I want to map each matter’s fee types to the correct trust or operating account so that funds are deposited compliantly without manual bookkeeping."
Description

Enable per-matter configuration that maps fee types (e.g., retainers, flat fees, costs, contingency advances) to designated bank accounts (IOLTA/trust vs operating). Support jurisdiction-aware selection of multiple trust accounts, firm-wide defaults, and per-matter overrides. Apply mappings at intake, estimate, invoice, and payment capture to ensure correct deposit routing. Validate mapped accounts for type compatibility, log all changes with who/when, and allow bulk import of mappings for existing matters. Expose mapping via API and UI with inline guidance.

Acceptance Criteria
Create and Save Per‑Matter Fee‑to‑Account Mapping in UI
Given an existing matter and a user with Billing Admin or Owner permission And the matter jurisdiction is set When the user maps Retainer -> Trust A, Flat Fee -> Operating, Costs -> Operating, Contingency Advance -> Trust B in Matter Settings > TrustSafe Routing and clicks Save Then only compatible account options are selectable per fee type and jurisdiction And the system saves the mappings and shows a success confirmation And reloading the page returns the saved mappings unchanged And mapping Retainer to an Operating account displays "Incompatible account type" and blocks Save
Firm‑Wide Defaults and Per‑Matter Overrides
Given firm‑wide default fee‑to‑account mappings exist When a new matter is created Then it inherits the firm defaults When a per‑matter override is saved Then the override is used for all future routing for that matter And clearing an override re‑applies the current firm default for that fee type And updating firm defaults updates matters that have no per‑matter override for the affected fee type And matters with overrides remain unchanged
Jurisdiction‑Aware Trust Account Selection
Given the firm has multiple trust accounts tagged by jurisdiction and operating accounts And a matter’s jurisdiction is set to State X When the user selects a trust account for Retainer mapping Then only trust accounts tagged for State X are shown And if none exist, the UI displays guidance to add a trust account for State X and disables Save And multiple trust accounts for State X are selectable And switching the matter’s jurisdiction refreshes the selectable trust accounts accordingly
Routing Applied at Intake, Estimate, Invoice, and Payment Capture
Given a matter has valid fee‑to‑account mappings saved When an intake retainer payment is captured via e‑sign link Then the payment is deposited to the mapped trust account for Retainer When an estimate or invoice is generated with only Flat Fee line items and paid Then the deposit routes to the mapped operating account When an invoice contains line items that map to different account types Then the system prevents a single combined payment, prompts for separate payments per account type, and no payment is created until the rule is satisfied And each completed payment’s transaction record shows the destination bank account ID matching its fee type mapping
Audit Log of Mapping Changes
Given audit logging is enabled When a mapping is created, updated, or deleted via UI or API Then an immutable log entry is recorded with matter ID, changed fee types, old and new account IDs, actor (user ID or API client ID), source (UI/API), and UTC timestamp And log entries are viewable in Matter > History and exportable as CSV And attempting to modify a mapping without permission is denied and logged with actor and reason
Bulk Import of Per‑Matter Mappings
Given a CSV file with headers MatterID, FeeType, AccountID When the user uploads the file to Bulk Import > Routing Mappings Then the system validates each row (matter exists, fee type valid, account exists, jurisdiction/account‑type compatible, no duplicate rows) And valid rows are applied idempotently (no change if identical mapping already exists) And invalid rows are rejected with per‑row error reasons And the import results summary shows total rows processed, applied, skipped, and failed And an optional Overwrite flag, if enabled, replaces existing per‑matter overrides for included fee types
API for Reading and Writing Mappings
Given a valid API token with scope routings:read and routings:write When a client calls GET /v1/matters/{matterId}/routing-mappings Then the API returns 200 with the current mappings per fee type and account IDs When a client calls PUT /v1/matters/{matterId}/routing-mappings with a complete mapping payload Then compatible mappings are saved and 200 is returned; incompatible mappings return 400 with error details per fee type And unauthorized or forbidden requests return 401/403 respectively And 404 is returned for non‑existent matters And all write responses include the actor client ID in the audit log
Automated Classification & Split Routing
"As a billing coordinator, I want payments to be auto-classified and split to the right accounts so that I don’t have to manually separate trust and operating funds."
Description

Automatically classify incoming payments by line item and route funds to multiple accounts within a single transaction (e.g., retainer to trust, earned fixed fee to operating). Parse invoices and payment intents to determine trust vs operating allocations, handle minimum trust balance replenishments, calculate and route refunds/chargebacks back to the original source and account, and support card/ACH/lockbox inputs. Ensure idempotent posting, retry-safe webhooks, and reconciliation metadata (payment ID, matter ID, allocation breakdown) for downstream reporting.

Acceptance Criteria
Split Routing of Mixed Payment by Line Item
Given an invoice INV-123 with line items tagged trust:retainer amount 1500.00 USD and operating:earned_fee amount 500.00 USD, and Matter M-123 mapped to Trust T-001 and Operating O-001 When the client pays 2000.00 USD in a single transaction via card Then the system classifies 1500.00 USD as trust and routes to T-001, and classifies 500.00 USD as operating and routes to O-001 And a single external charge is recorded with two internal allocations matching the line-item amounts And the Matter M-123 trust ledger increases by 1500.00 USD with entry type deposit, and operating revenue increases by 500.00 USD And reconciliation metadata is persisted: paymentId, providerEventId, matterId M-123, invoiceId INV-123, allocation breakdown [{accountId:T-001,amount:1500.00,type:trust},{accountId:O-001,amount:500.00,type:operating}] And the transaction is marked non-commingled and auditable end-to-end
Minimum Trust Balance Replenishment
Given Matter M-456 has a minimum trust balance of 1000.00 USD and current available trust is 200.00 USD, and accounts Trust T-001 and Operating O-001 are mapped And an invoice contains only an earned fee line item of 600.00 USD When the client pays 1200.00 USD via ACH Then 800.00 USD is allocated to trust replenishment to reach the 1000.00 USD minimum and routed to T-001, and 400.00 USD is allocated to operating and routed to O-001 And receipts, client-facing breakdown, and ledger entries reflect the allocations and resulting trust balance of 1000.00 USD And if the payment is insufficient to fully replenish and pay fees, replenishment to the minimum takes priority and any remainder is applied to earned fees; no allocation to operating occurs until trust minimum is met And guardrails prevent any portion of replenishment from being routed to operating
Refunds and Chargebacks Routed to Original Source
Given an original payment P-001 allocated 1500.00 USD to Trust T-001 and 500.00 USD to Operating O-001 on Matter M-123 When a 400.00 USD partial refund is issued against the earned fee Then 400.00 USD is returned from O-001 to the original payment method and operating ledger posts a refund entry; trust balances are unchanged When a 300.00 USD client trust refund is issued on Matter M-123 Then 300.00 USD is disbursed from T-001 to the client's original payment method, recorded as a trust refund, and reduces the trust ledger accordingly When a 200.00 USD chargeback is received from the card network on P-001 Then the system reverses allocations proportionally to the original split (150.00 USD from T-001, 50.00 USD from O-001), posts reversal entries, and updates ledgers And all refunds/chargebacks include reconciliation metadata linking to original paymentId P-001 and allocationIds; no cross-account transfers occur that would commingle funds
Idempotent Posting and Retry-Safe Webhooks
Given the payment provider may deliver the same event (providerEventId E-789) multiple times and concurrently When the event is processed more than once due to retries or concurrency Then payment, allocation, and ledger records are created exactly once and are not duplicated And subsequent duplicate deliveries are acknowledged with success without creating new financial entries And idempotency keys and event fingerprints are persisted for at least 7 days And audit logs show a single processed timestamp and count of duplicate deliveries ignored And processing is safe to retry after service restarts without side effects
Per-Matter Account Mapping and Real-Time Trust Ledger
Given Matter M-789 is mapped to Trust T-002 and Operating O-002 When a split-routed payment posts for M-789 Then the trust ledger for M-789 is updated within 2 seconds of webhook receipt with an entry containing date/time, amount, type (deposit/release/refund/chargeback), counterparty, allocationId, and resulting balance And any payment referencing a matter without a complete mapping is blocked from posting, no funds are moved, and the item is placed in an exceptions queue with a clear error And ledger balances can be recalculated from entries to match account totals exactly (0.00 variance)
Multi-Input Support (Card, ACH, Lockbox)
Given payments may arrive via card capture, ACH settlement, or lockbox batch import When a card payment is captured successfully Then allocations are executed immediately on capture and routed according to line-item classification When an ACH payment is initiated Then no ledger postings occur until settlement; on settlement, allocations are executed; if an ACH return occurs, reversal entries are posted to the original accounts When a lockbox batch is imported and remittance references an invoice or matter Then the payment is classified and split-routed accordingly; unmatched items are placed in a suspense queue with no funds routed until resolved And all input types produce identical reconciliation metadata and maintain idempotency semantics
Reconciliation Metadata and Reporting Traceability
Given any financial event (payment, allocation, refund, chargeback, reversal) Then metadata is stored and required: paymentId, providerEventId, matterId, clientId, invoiceId, currency, allocation array [{allocationId,accountId,accountType,amount,ledgerType,timestamp}], and createdBy actor And an API/export endpoint returns the exact metadata for a given date range and matter, and each allocationId can be traced from bank transaction to matter ledger And nightly reconciliation produces a report that ties allocation totals to bank account statements with 100% completeness; any variance is flagged with itemized discrepancies and zero unchecked variances remain
Commingling Guardrails
"As a managing partner, I want guardrails that stop improper trust handling so that we remain compliant and audit-ready."
Description

Provide pre- and post-transaction validations that prevent commingling: block deposits to operating for retainers, block non-client withdrawals from trust, require matter association for any trust movement, enforce available-balance checks, and stop transfers that would cause a negative client balance. Offer guided error messages with remediation options (e.g., reclassify line item, choose correct account), plus optional dual-approval for trust disbursements above thresholds. Maintain an immutable audit trail of attempted violations and resolutions.

Acceptance Criteria
Block Retainer Deposits to Operating Accounts
- Given a payment line item is tagged "Retainer" and the destination account type is Operating, when the user attempts to post the transaction, then the system blocks posting and displays an error: "Retainers must be deposited to trust (IOLTA)." - Given the user selects "Select Trust Account" from the error banner and chooses a valid IOLTA account, when they resubmit, then the transaction posts successfully to the trust account and is reflected in the client/matter trust ledger. - Given the user selects "Reclassify as Flat Fee" from the error banner and retains the Operating destination, when they resubmit, then the transaction posts successfully to the operating account and is reflected in the income ledger, not the trust ledger. - Then no ledger balances change on a blocked attempt; only successful resubmissions affect ledgers. - Then an audit entry is written for the blocked attempt with fields userId, timestamp, matterId (if provided), lineItemId, amount, attemptedAccountType, ruleId "COMMINGLE_001", decision "Blocked".
Block Non‑Client Withdrawals from Trust
- Given a withdrawal is initiated from a trust account without an associated client/matter, when the user attempts to submit, then the system blocks the transaction and displays: "Trust disbursements require a client/matter." - Given the payee is a third party and no client/matter is selected, when the user attempts to submit, then the system blocks and requires selection of a client/matter related to the funds. - Given the user chooses a remediation option "Select Matter" and associates a valid matter, when they resubmit, then the transaction proceeds only if available balance checks pass. - Given the user chooses "Switch to Operating Account" for a non‑trust disbursement, when they resubmit, then the transaction posts to Operating and no trust ledger is affected. - Then an audit entry is recorded for each blocked attempt with ruleId "COMMINGLE_002" and decision "Blocked".
Require Matter Association for All Trust Movements
- Given the selected source or destination account is Trust, when the user focuses out of the Matter field, then inline validation marks the field required within 200 ms if empty. - Given a user submits a form for a trust deposit, transfer, or withdrawal with no matter selected, when they click Submit, then submission is prevented and an error banner states: "A client/matter is required for all trust transactions." - Given an API client posts a trust transaction without matterId, when processed, then the API responds 400 with errorCode "MISSING_MATTER_FOR_TRUST" and no transaction is created. - Then the Submit/Approve actions remain disabled in the UI until a valid matter is selected for trust transactions.
Prevent Negative Client Trust Balances via Available‑Balance Checks
- Given a trust disbursement or transfer-out is created for a matter, when the amount exceeds the matter’s available trust balance (including pending transactions), then the system blocks submission and displays: "Insufficient trust balance. Available: $X. Requested: $Y." - Given two disbursement requests for the same matter are submitted concurrently that together exceed the available balance, when processed, then only the first to reserve funds succeeds and the second is blocked with a stale-balance message. - Then available balance calculation includes same-day pending credits/debits and any holds for pending approvals. - Given the user selects "Adjust Amount" remediation, when they enter an amount ≤ available balance, then the transaction can be submitted successfully. - Then all blocked attempts are logged with ruleId "COMMINGLE_003" and the prior and post-check balances captured in the audit entry.
Guided Error Messages with Remediation Options
- Then every validation error related to commingling includes: a human-readable cause, a rule short code (e.g., COMMINGLE_001), and up to two contextually relevant remediation actions (e.g., "Select Trust Account", "Reclassify as Flat Fee"). - Given a user clicks a remediation action from an error banner, when invoked, then the system navigates to the correct field or opens the correct modal with the relevant control focused within 300 ms. - Then error banners meet accessibility requirements: ARIA live announcement and color contrast ratio ≥ 4.5:1. - Then choosing a remediation action and successfully resubmitting clears the error state and results in a single posted transaction (no duplicates).
Dual‑Approval for High‑Value Trust Disbursements
- Given a trust disbursement amount exceeds the firm’s configured approval threshold, when the requester submits, then the request enters status "Pending First Approval" and no funds are disbursed. - Given the first approver approves, when recorded, then status changes to "Pending Second Approval" and funds are placed on hold against the matter’s available balance. - Given the requester attempts to approve their own disbursement at any stage, when attempted, then the system blocks the action with error: "Self-approval is not permitted." - Given a second distinct approver approves within the configured time window, when recorded, then the disbursement posts and the trust ledger updates; otherwise, after timeout, the request auto-expires and the hold is released. - Then all approval, rejection, and expiry events are logged with ruleId "COMMINGLE_004", approverIds, timestamps, and prior/after balances.
Immutable Audit Trail for Violations and Resolutions
- Then every blocked, overridden, or remediated commingling-related event writes an append-only audit entry containing: eventId, timestamp (UTC), userId, matterId, accountId, amount, actionType, ruleId, decision, remediationAction (if any), approvalIds (if any), and source IP. - Then audit entries are immutable to all user roles; any attempt to edit or delete returns HTTP 403/"Forbidden" and is itself logged as a security event. - Given an auditor exports a date-bounded report up to 10,000 events, when requested, then the export completes within 2 seconds and includes a SHA-256 hash chain that validates integrity; tampering with any record causes chain verification to fail. - Then the audit trail UI/API supports filtering by ruleId, matterId, userId, and date range, returning results consistently ordered by timestamp descending.
Instant Trust Ledgers & Statements
"As a paralegal, I want real-time trust ledgers and statements so that I can answer client balance questions and prepare reconciliations quickly."
Description

Generate per-matter trust ledgers in real time as payments, transfers, and disbursements occur. Support three-way reconciliation by maintaining client sub-ledgers, trust account general ledger, and bank balance references with reconciliation status. Provide dated statements, filters, exports (PDF/CSV), period locks, and change logs. Enable statement sharing to clients via secure link and include line-item justifications tied to invoices and disbursements.

Acceptance Criteria
Real-Time Per-Matter Trust Ledger Update on Receipt
Given a new trust deposit of $X is successfully posted for Matter M When the gateway confirms settlement and TrustSafe Routing classifies it as trust Then the Matter M trust ledger shows a new Deposit line within 2 seconds with amount, payer, method, reference ID, user, and ISO-8601 timestamp And the running balance for Matter M increases by $X and matches the client sub-ledger and trust general ledger And the transaction carries an immutable transaction ID and appears in the change log as Created with no modifications And the ledger line includes a justification/reference to the payment record
Disbursement to Operating Linked to Invoice
Given an approved invoice I for Matter M with trust funds available ≥ invoice total When a disbursement from trust to operating is executed against invoice I Then the Matter M trust ledger records a Disbursement line with invoice I reference, justification, payee, method, amount, and running balance decrease And the client sub-ledger and trust general ledger decrease by the disbursed amount in sync And the system prevents the disbursement if it would cause a negative trust balance and displays an Insufficient Trust Funds error And the change log records who initiated, timestamp, and the linkage to invoice I
Three-Way Reconciliation Status per Period
Given a reconciliation period with an entered bank statement ending balance, date, and statement reference When cleared ledger items are matched to bank transactions and the difference equals $0.00 Then the reconciliation status for that period is set to Reconciled and displays reconciler, timestamp, and reconciliation report ID And uncleared items remain listed with carry-forward status without blocking reconciliation if the difference is $0.00 And if the difference is not $0.00, status is Out of Balance with the variance amount highlighted and disbursements from trust are blocked until resolved (role-configurable) And the reconciliation snapshot stores client sub-ledger total, trust GL balance, and bank ending balance for audit
Filtered Statement Generation and Export (PDF/CSV)
Given a user selects Matter M, a date range, and optional filters (transaction type, user, min/max amount) When a trust statement is generated Then the on-screen statement shows chronological lines with date, type, description/justification, reference, debit, credit, and running balance columns And totals for deposits, disbursements, and ending balance are displayed for the selected range And exporting to PDF produces a paginated file with firm name, matter ID, statement date range, page numbers, and the same columns and totals And exporting to CSV produces a UTF-8 file with header row and one row per transaction preserving numeric precision to 2 decimals And file names follow the pattern MatterID_TrustStatement_YYYYMMDD-YYYYMMDD.{pdf|csv}
Period Locking and Post-Lock Adjustment Auditability
Given a user with appropriate role locks the trust ledger for a closed period P When any user attempts to edit, delete, or backdate a transaction within P Then the system blocks the action and displays Period Locked with guidance to create an adjustment in the next open period And any adjustment is posted with an Adjustment type, reason code, and link to the original transaction, without altering the original And unlocking a period requires Admin role, mandatory reason entry, and creates a change log entry with before/after lock states and timestamp And all change log records are immutable and exportable for audit
Secure Client Sharing of Trust Statement
Given a user selects Share for a generated Matter M trust statement When a secure link is created Then the link uses a single-use token, firm-configurable expiration (default 14 days), and HTTPS only And the client view shows only Matter M data for the selected range with line-item justifications and allows PDF download; CSV export is disabled by default And access attempts are logged with timestamp, IP, user-agent, and success/failure; the sender can revoke access at any time And the link cannot be enumerated and returns 404 after expiration or revocation
Integrity, Concurrency, and Idempotency Controls
Given transactions may be created by multiple users or webhooks concurrently When two identical deposit requests are received with the same idempotency key Then only one ledger entry is created and balances remain correct And all monetary values are stored in cents (integer) and displayed rounded to 2 decimals using the firm currency And operations are ACID within a matter: balances never temporarily go negative and reads reflect committed data And system clocks are normalized to UTC with display in firm time zone, and each entry includes both UTC and display timestamps
Compliance Alerts & Monitoring
"As a firm administrator, I want real-time compliance alerts so that I can resolve issues before they become audit findings."
Description

Issue real-time alerts for low client trust balances, attempted commingling, stale unearned funds, unreconciled periods, out-of-jurisdiction trust account use, and impending overdrafts. Provide alert channels (in-app, email, mobile push), suppression windows, severity levels, and escalation rules. Surface a compliance dashboard with open issues, aging, and resolution workflows tied to each matter and transaction.

Acceptance Criteria
Trust Balance Risk Alerts (Low & Overdraft)
Given a matter trust balance including cleared and pending items, When a pending or requested disbursement would cause the projected balance to fall below $0, Then block the disbursement, show “Insufficient client trust funds,” and create a Critical alert linked to the matter, transaction, and trust account. Given a configurable low-balance threshold per matter (default $500), When the effective balance (cleared minus holds) drops below the threshold, Then create a High alert within 60 seconds via the user’s configured channels and add it to the compliance dashboard. Given a duplicate-alert suppression window for low-balance alerts (default 24 hours), When the low-balance condition persists, Then do not emit duplicate alerts within the window unless severity escalates or the balance decreases by an additional 20%. Given a low-balance or overdraft alert is acknowledged, When acknowledged by an assignee, Then pause escalation timers and retain the alert as Open until the condition clears or a resolution action is recorded.
Attempted Commingling Block & Alert
Given per-matter account mapping routes retainers to trust (IOLTA) and flat fees to operating, When a user attempts to post a retainer to operating or a flat-fee payment to trust, Then block the transaction, present corrective guidance, and create a Critical commingling alert with user, timestamp, matter, accounts, and amount recorded in the audit log. Given an external integration import includes mixed allocations into a single account, When detected, Then auto-split per mapping if unambiguous; otherwise reject the import line, create a Critical commingling alert, and notify the integration owner. Given a commingling alert remains unacknowledged for 4 hours (configurable), When the timer expires, Then escalate to the matter owner and firm owner and increase severity to Critical if not already.
Stale Unearned Funds Detection
Given client trust funds associated with a matter have had no earn or refund activity for 90 days (configurable), When the inactivity threshold is reached, Then create a Medium alert listing the matter, client, amount, and last activity date and start an aging timer. Given a stale-funds alert ages to 120 days (configurable), When the threshold is reached, Then escalate the alert to High and notify the assigned attorney and firm owner via configured channels. Given a resolution action of “refund unearned” or “apply to invoice” is posted, When the ledger updates, Then automatically close the alert, record resolver, timestamp, and resolution reason in the audit log, and update dashboard counts.
Unreconciled Period Alerts
Given a trust account month has ended, When no reconciliation is marked complete within 30 days of month end (configurable), Then create a High alert for the account owner and display the open period on the compliance dashboard. Given a reconciliation is completed with statement attachment and reconciler specified, When saved, Then close the alert and record reconciler, completion timestamp, and attachment reference in the audit log. Given no reconciliation action is taken 15 days after the initial alert (configurable), When the timer elapses, Then escalate the alert to Critical and notify all firm admins.
Out-of-Jurisdiction Trust Account Use
Given each matter has a jurisdiction and each trust account has allowed jurisdictions defined, When a user initiates a deposit or disbursement from a trust account not allowed for the matter’s jurisdiction, Then block the action and create a High alert with reason “Out-of-jurisdiction trust use,” including matter, account, jurisdiction, and attempted amount. Given a matter’s jurisdiction is changed, When the change is saved, Then revalidate trust-account mappings and create High alerts for any active retainers or scheduled disbursements that are now non-compliant. Given an out-of-jurisdiction alert is resolved by remapping to a compliant account and re-posting, When the corrective transaction posts successfully, Then mark the alert Resolved and capture the corrective transaction ID in the alert history.
Alert Delivery, Suppression, Severity & Escalation Controls
Given firm-wide alert settings are configurable, When an admin sets channel preferences (in-app, email, push) and quiet hours per role/user, Then subsequent alerts deliver only to enabled channels and respect quiet hours for non-Critical severities. Given suppression windows are defined per alert type, When the same condition persists, Then suppress duplicate alerts within the window unless severity increases or a different actor initiates a new triggering event. Given escalation rules specify acknowledge within 4 hours and resolve within 3 business days (configurable), When timers expire without action, Then escalate per chain (assignee → matter owner → firm owner) and increase severity one level at each step, with each escalation recorded in the audit log. Given a test-mode toggle is enabled, When “Send test alert” is invoked, Then deliver a clearly labeled TEST alert to selected channels without creating a production dashboard item.
Compliance Dashboard & Resolution Workflow
Given the compliance dashboard is opened, When there are open alerts, Then display counts by type, severity, account, and jurisdiction with aging badges in days and provide filters for matter, user, account, jurisdiction, severity, and date range. Given an alert is selected, When “View details” is clicked, Then show a panel with linked matter and transaction, current status (Open, Acknowledged, Resolved, Dismissed), full history, and available next actions. Given a user performs a resolution action (e.g., correct allocation, issue refund, complete reconciliation), When the action is confirmed, Then transition the alert to Resolved, record resolver, timestamp, and resolution reason code, and remove it from open counts. Given multiple alerts are selected, When “Acknowledge” is applied in bulk, Then set status to Acknowledged for selected alerts and start resolution timers for each.
Bank & Processor Integrations
"As an operations lead, I want direct bank and processor integrations so that routing, settlements, and reconciliations stay accurate and up to date."
Description

Integrate with supported banks and legal payment processors (e.g., LawPay, Stripe with trust-compliant settings) to retrieve account identifiers and types, ingest webhooks for settlements, refunds, and chargebacks, and fetch bank feed transactions for reconciliation. Support OAuth-based connections, token rotation, sandbox/test modes, and fallback CSV import when direct connections are unavailable. Enforce IOLTA/trust account constraints exposed by the processor and surface settlement delays and fees in allocation metadata.

Acceptance Criteria
OAuth Connection and Account Discovery
Given a firm user selects a supported processor (LawPay or Stripe trust-compliant) from Integrations When they complete OAuth authorization Then the system stores access and refresh tokens encrypted at rest and scoped to the workspace And the connection record includes merchant/account identifiers and account types (trust/IOLTA vs operating) And the connection health displays Connected within 10 seconds of OAuth callback And per-matter mapping allows selecting discovered trust and operating accounts for routing And multiple distinct processor connections can coexist in one workspace
Enforcement of Trust/IOLTA Constraints
Given a payment allocation is requested When a trust retainer is routed to an operating account or a flat fee to a trust account Then the request is rejected with HTTP 422 and a user-visible error: Account type mismatch; no transaction is initiated And if the processor flags an account as trust-compliant, processing fees must not be deducted from that account And if a webhook indicates fees were deducted from a trust account, a compliance alert is created within 60 seconds and the settlement is flagged for review
Webhook Ingestion for Settlements, Refunds, and Chargebacks
Given a signed webhook from a connected processor When events of type settlement, refund, chargeback, payout, or payout_failed are received Then the signature is verified and the event is processed idempotently And payment status, trust ledger entries, and allocation metadata (fees, fee payer, settlement schedule, estimated deposit date) are updated And invalid or replayed signatures result in 401 and the event is ignored but logged And average processing latency is under 2 seconds; 99th percentile under 5 seconds And delivery retries are handled with exponential backoff; failures after 3 attempts are placed on a dead-letter queue and trigger an alert
Bank Feed Retrieval and Reconciliation
Given a connected bank account via OAuth or a CSV file import When the bank feed sync runs hourly or is triggered on-demand Then new transactions are fetched with account type, amount, posted date, reference, and balance And transactions are matched to processor settlements by amount and date within a +/- 2 business day tolerance And duplicates are prevented using a stable deduplication key (provider id/fitid + amount + date) And CSV import validates required columns, reports row-level errors, and ingests valid rows; a summary is presented on completion And each settlement attains a reconciliation status of Matched, Partially Matched, or Unmatched
Sandbox/Test Mode Isolation
Given a processor connection is set to Test mode When test transactions and webhooks are received Then data is labeled Test, isolated from production ledgers and reports, and excluded from compliance alerts And a visible banner indicates Sandbox in integration and ledger views And production and test data can coexist across connections without cross-contamination
Token and Webhook Secret Rotation
Given an OAuth access token is within 24 hours of expiry When the background refresh job runs Then the token is refreshed automatically and stored securely; the connection remains uninterrupted And after 3 failed refresh attempts, the connection health is set to Action Required and an alert is sent to admins And webhook signing secrets can be rotated; during a configurable overlap window, both old and new secrets are accepted
Settlement Delays and Fees in Allocation Metadata
Given a payment has been authorized and subsequently settled by the processor When viewing allocation details via UI or the GET /allocations/{id} API Then the metadata includes processor name, processor payment id, gross amount, fee amounts by type (processing, refund, chargeback), fee payer, net amount, payout account, expected payout date, and settlement delay in business days And this metadata is exportable in CSV and visible in matter-level payment tables
Role-Based Access & Approvals
"As a compliance officer, I want role-based controls and approvals so that only authorized staff can move trust funds and every action is auditable."
Description

Implement granular permissions for viewing balances, initiating trust deposits/withdrawals, editing mappings, and approving disbursements. Support dual-approval flows with configurable thresholds, required e-sign approvals for client refunds, and full audit logging of approver identity and timestamps. Restrict sensitive actions on trust accounts to designated users and enforce session re-authentication for high-risk operations.

Acceptance Criteria
Balance Visibility Permission Enforcement
Given a user lacks the "View Trust Balances" permission, When they open a matter or account dashboard, Then all trust and operating balances are hidden/redacted and no numeric balance values are displayed. Given a user has only the "View Trust Balances" permission, When viewing a matter with trust activity, Then they can view read-only balances and ledger entries but cannot initiate transactions or edit mappings (controls hidden or disabled). Given permissions are changed by an admin, When the user refreshes or re-authenticates, Then visibility updates reflect the new permissions within 60 seconds. Given an API request to balance endpoints, When the caller lacks "View Trust Balances", Then the API returns 403 and no balance fields; When the caller has the permission, Then the API returns 200 with balance fields populated.
Trust Deposit/Withdrawal Initiation Restrictions
Given a user lacks "Initiate Trust Deposit", When attempting to create a trust deposit, Then the action is blocked with a 403 and a visible "Insufficient permissions" error. Given a user lacks "Initiate Trust Withdrawal", When attempting to create a trust withdrawal/disbursement, Then the action is blocked with a 403 and a visible "Insufficient permissions" error. Given a user is designated only for certain trust accounts, When initiating a transaction on a non-designated trust account, Then the action is blocked and the UI/API indicates account designation is required. Given a user has the appropriate permission and designation, When initiating a trust transaction, Then a draft is created in "Pending Approval" state with the initiator recorded and no funds are moved prior to approval.
Dual-Approval Disbursement Thresholds
Given a firm-level trust disbursement threshold of $X, When a disbursement amount is greater than or equal to $X, Then two distinct approvers with "Approve Disbursement" permission are required and the initiator cannot approve their own request. Given a disbursement amount less than $X, When initiated, Then a single approver is sufficient per policy settings. Given a matter-specific threshold exists, When a disbursement is initiated for that matter, Then the matter threshold overrides the firm default. Given the first approver approves, When approval is recorded, Then eligible second approvers are notified via in-app and email within 1 minute. Given the second approver denies, When the denial is submitted, Then the disbursement is marked Rejected and cannot be executed without a new initiation. Given an approver attempts both approval steps, When trying to approve the second step, Then the system blocks it and indicates separate approvers are required.
Client Refund E‑Sign Approval Requirement
Given a transaction of type "Client Refund" is created, When it moves to approval, Then the system generates a refund authorization for client e-sign with the correct client, matter, amount, and destination details prefilled. Given the client e-sign is not completed, When an approver attempts to finalize the refund, Then the system blocks approval and displays/returns "Awaiting Client E‑Signature". Given the client completes e-sign, When the refund is approved, Then the signed document, envelope ID, signer identity, and timestamp are attached to the transaction and visible in the audit log. Given a pending refund is canceled, When cancellation occurs, Then any outstanding e-sign envelope is automatically voided and the event is logged.
High-Risk Operation Session Re-Authentication
Given a user initiates a high-risk operation (approve trust disbursement, edit account mapping, change approval thresholds, add/remove approvers), When the last successful re-authentication was more than 10 minutes ago, Then the user is prompted for password and configured MFA and the operation is paused until success. Given the user fails or cancels re-authentication, When the operation would proceed, Then the operation is aborted and a non-success response is shown/returned with code "reauth_failed". Given the user successfully re-authenticates, When the operation completes, Then the re-auth timestamp and method are recorded and linked to the action in the audit log. Given an API call to a high-risk endpoint lacks a valid re-auth token, When processed, Then the API returns 401 with error "reauth_required".
Audit Logging Completeness for Approvals and Changes
Given any trust transaction initiation, approval/denial, mapping edit, or threshold change occurs, When the action is saved, Then an immutable audit log entry is created with: action type; actor user ID and role; target matter/account/transaction IDs; before/after values; IP and user agent; UTC timestamp with millisecond precision; approval step (1 or 2) and approver order; e-sign envelope ID (if any); and re-auth status and timestamp. Given a user exports the audit log, When a date range, user, matter, or action-type filter is applied, Then the export contains matching entries with all fields and includes a tamper-evident hash for each record. Given an approval is delegated or escalated, When the approver changes, Then the audit log records the original approver, new approver, delegator, and timestamps.
Per-Matter Account Mapping Edit Controls
Given a user lacks the "Edit Account Mapping" permission, When they attempt to change a matter’s trust/operating routing, Then controls are disabled in the UI and API returns 403 for edit requests. Given a matter has a nonzero trust balance, When a mapping change is submitted, Then a justification note is required and the change enters "Pending Mapping Approval" for users with "Approve Mapping Changes". Given a pending mapping change is approved, When approval is recorded, Then the new mapping applies only to future transactions, the effective timestamp is saved, and prior ledger entries remain unchanged. Given a pending mapping change is rejected, When rejection is recorded, Then no changes are applied and the requester receives an in-app and email notification.

Sign‑to‑Pay

Embeds payment directly inside the e‑sign packet so clients authorize the retainer before documents are considered complete. Supports ACH, cards, and Apple/Google Pay with clear fee disclosures, smart default amounts, and fallback pay links—speeding conversion and reducing after‑sign chasing.

Requirements

Embedded Pay in E‑Sign Flow
"As a solo attorney, I want clients to pay the retainer while signing so that I capture funds without extra follow‑ups and move the matter forward immediately."
Description

Embed a secure payment step directly inside the CaseSpark e‑signature packet, allowing clients to authorize and submit retainers within the same guided workflow. The payment pane is contextually linked to the specific intake/matter and pre-populates client details from intake to minimize friction. The flow supports amount entry, method selection, and consent capture before the final signature confirmation, with real-time validation and clear progress indicators. Events and webhooks expose payment outcomes to the e‑sign envelope so subsequent steps (like finalizing documents) can react without leaving the packet.

Acceptance Criteria
Payment Step in E‑Sign Blocks Completion Until Authorized
Given an active e‑sign packet for a matter with a required retainer > 0 When the signer reaches the payment step Then a payment pane is displayed within the packet with a visible step indicator including "Payment" Given the signer has not completed payment When viewing the finalization controls Then "Complete/Finish Signing" is disabled and labeled "Awaiting Payment" Given the signer successfully authorizes a payment for the required amount When the processor returns success Then the UI enables "Complete/Finish Signing" within 3 seconds and displays a "Paid" badge with the authorized amount Given a payment attempt is declined When the processor returns a failure code Then an inline error with the processor code/description is shown and the signer may retry up to 5 times before a fallback pay link is offered Given the signer clicks the fallback pay link When leaving the payment pane Then the envelope status is set to "Awaiting Payment" and documents are not marked complete until a successful payment webhook is received
Contextual Pre‑Fill from Intake and Matter Linking
Given the matter has intake data (full name, email, phone, billing address) When the signer opens the payment pane Then full name and email are pre‑populated and read‑only; phone and billing address are pre‑populated and editable Given any required field (name, email, country, ZIP/postal code) is missing or invalid When attempting to proceed Then inline validation highlights the field and blocks submission until corrected Given payment is submitted When creating the charge/authorization Then payment metadata includes matterId, envelopeId, signerId, and intakeContactId and is persisted to the envelope audit log
Multi‑Method Payments with Wallet Eligibility and Fallback
Given the merchant account enables Cards, ACH, and Wallets When the signer opens the payment pane on an eligible device/browser Then Card and ACH are displayed, and Apple Pay or Google Pay are displayed only when eligibility and merchant configuration are satisfied Given a method is disabled in merchant configuration When the payment pane loads Then the disabled method is not shown as an option Given a wallet method is selected When the wallet sheet is invoked Then payer details returned by the wallet pre‑fill the form (where applicable) and a tokenized payment is submitted on authorization Given a wallet authorization is canceled or fails When returning to the payment pane Then the user remains in the payment step with all previously entered data preserved and may choose another method or retry Given the PSP for a selected method is unavailable When attempting to submit Then a clear error is shown and a fallback pay link is offered without exiting the envelope
Smart Default Retainer Amount with Editable Bounds
Given the matter has a configured smart default retainer and optional min/max bounds When the payment pane loads Then the amount field is pre‑filled to the smart default, displays the configured currency, and enforces two‑decimal precision Given the signer edits the amount When the new value is outside min/max bounds or ≤ 0 Then submission is blocked and an inline message displays the allowed range Given the signer enters a valid amount within bounds When proceeding to payment Then the updated amount is used for authorization/charge and reflected in all subsequent events and receipts
Fee Disclosure, Terms, and Explicit Consent Capture
Given any processing fee, surcharge, or discount is configured When the payment pane is displayed Then a clear breakdown shows Amount, Fees/Discounts, and Total before any payment can be submitted Given ACH is selected When reviewing the payment terms Then NACHA authorization text is displayed and an "I authorize ACH debit" checkbox is required to enable the Pay button Given Card or Wallet is selected When reviewing the payment terms Then a required "I agree to the payment terms" checkbox is displayed and the Pay button remains disabled until checked Given the payer clicks Pay When authorization is captured Then the system records consent artifacts (timestamp, IP address, user agent, terms version, checkbox states) and attaches them to the envelope audit trail
Real‑Time Validation, Error Handling, and Safe Retry
Given Card entry When the payer inputs number, expiry, and CVC Then Luhn check, expiry > current month, and CVC format validation occur client‑side with immediate feedback; BIN detection identifies brand and country Given SCA/3DS is required by the issuer When submitting the card Then a 3DS challenge is invoked and on success the payment proceeds; on failure, an actionable error is shown and the payer may retry without data loss Given ACH entry When the payer inputs routing and account numbers and account name Then routing checksum and account number length are validated client‑side and ACH terms are required Given a transient network or PSP error occurs When retrying the same payment Then an idempotency key prevents duplicate charges and previously entered data persists; after 3 consecutive transient failures a fallback pay link is offered Given a validation error is corrected When the field becomes valid Then the error clears immediately and the Pay button state updates accordingly
Payment Outcome Events and Webhooks Drive Envelope State
Given a payment succeeds When the provider returns success Then a PaymentAuthorized event is written with payload {envelopeId, matterId, signerId, paymentId, method, last4/tokenTail, amount, currency, status, createdAt} and the envelope step advances to "Ready to Sign" or finalizes automatically if all signatures are complete Given a payment fails or is canceled When receiving the failure from the provider or wallet Then a PaymentFailed event is written with errorCode and errorMessage and the envelope remains in "Awaiting Payment" Given webhook delivery to CaseSpark fails When the provider retries Then deliveries are retried at least 10 times over up to 24 hours with exponential backoff and processed idempotently using eventId and paymentId Given duplicate or out‑of‑order events are received When applying them to the envelope Then only the latest applicable status is applied and earlier sequence numbers are ignored Given a payment success event is received after all required signatures are captured When processing the event Then the envelope is marked complete and downstream document finalization triggers without user intervention
Multi‑Tender & Wallet Support
"As a client, I want to pay using my preferred method (ACH, card, or mobile wallet) so that I can complete onboarding quickly and conveniently."
Description

Offer clients ACH, credit/debit cards, and Apple Pay/Google Pay within the embedded payment pane, automatically detecting device/browser capabilities to surface eligible wallet options. Provide a consistent fallback to manual card/ACH entry when wallets are unavailable. Tokenize all payment methods, store payment intent identifiers securely, and support retries without retyping information. Surface method‑specific disclosures (e.g., ACH authorization language) and handle asynchronous confirmations (e.g., ACH) through callbacks that update the envelope state.

Acceptance Criteria
Apple Pay Availability on iOS/macOS Safari
Given a signer opens the embedded payment pane in the e‑sign packet on Safari with Apple Pay configured When the payment pane initializes Then an Apple Pay button is rendered, visible, and enabled And selecting Apple Pay invokes the native Apple Pay sheet with the retainer amount and merchant name And a link or toggle for “Other payment methods” expands to Card and ACH entry options And no Google Pay button is rendered in the DOM
Google Pay Availability on Android Chrome
Given a signer opens the embedded payment pane in the e‑sign packet on Chrome for Android with Google Pay set up When the payment pane initializes Then a Google Pay button is rendered, visible, and enabled And selecting Google Pay invokes the native Google Pay sheet with the retainer amount and merchant name And a link or toggle for “Other payment methods” expands to Card and ACH entry options And no Apple Pay button is rendered in the DOM
Wallet Unavailable Fallback to Card/ACH Entry
Given a signer is using a browser/device that does not support Apple Pay or Google Pay, or wallet capability checks fail When the payment pane initializes or a wallet selection returns “not available” Then no wallet buttons are shown (or they are removed) And the Card and ACH entry forms are immediately available without blocking errors And the signer can complete payment using Card or ACH successfully And a non-blocking message explains that wallet payments are unavailable on this device/browser
Payment Method Tokenization and Intent Persistence
Given a signer authorizes a payment via Card, ACH, Apple Pay, or Google Pay When the authorization/mandate is created with the payment service provider (PSP) Then a tokenized payment_method_id and a payment_intent_id (or equivalent) are stored server-side in encrypted storage And no raw PAN or bank account numbers are stored on CaseSpark systems; sensitive values are never logged And the envelope is associated with the stored identifiers for retries and status updates And tokens are retrievable only via authenticated service-to-service calls and appear masked in any audit logs
Payment Retry Without Retyping
Given an initial payment attempt fails or the signer reopens the payment step before the envelope is complete When the signer chooses Retry payment Then the previously tokenized payment method can be reused without re-entering card or bank details (subject to PSP token validity, minimum 24 hours) And the UI allows switching to a different method (Card, ACH, Apple Pay, Google Pay) without losing the ability to retry the original token And on success, the same payment_intent (or a new attempt linked to the envelope) is updated to succeeded and the payment step is marked complete And on failure, the token remains available for additional attempts until token expiry
Method-Specific Disclosures and Consent Capture
Given the signer selects ACH as the payment method When the ACH form is displayed Then NACHA-compliant authorization text including debit amount, authorization, and revocation terms is shown And a required consent checkbox or explicit authorization step is enforced before enabling Pay And the exact disclosure text version, timestamp, signer ID, IP address, and method type are stored with the envelope Given the signer selects Card or a Wallet method When the confirmation UI is displayed Then any applicable fees/surcharges and method-specific disclosures are clearly shown before submission And submission is blocked until the signer acknowledges any required consents
Asynchronous Confirmations Update Envelope State
Given an ACH payment is submitted and the PSP returns a pending status When webhook/callback events are received from the PSP Then Payment Pending (ACH) is reflected in the envelope until final status is known And upon a succeeded event, the envelope is updated to Payment Captured and the e‑sign packet is marked complete And upon a failed/returned event, the envelope is updated to Payment Failed and the payment step is reopened with Retry options using stored tokens And webhook processing is idempotent using event IDs to prevent duplicate updates
Transparent Fees & Surcharging Rules
"As a firm owner, I want transparent fee displays that comply with network and state rules so that clients understand costs and I avoid penalties or disputes."
Description

Present clear, itemized fee disclosures before authorization, showing base retainer, processing fees, and totals with real‑time updates. Support configurable firm policies to pass, share, or absorb fees, enforcing network and jurisdictional restrictions (e.g., no surcharging on debit, limits on surcharge rates, and trust‑account constraints). Log explicit client consent to fees and store a non‑editable audit trail with timestamp, IP, and disclosure text version for compliance and dispute resolution.

Acceptance Criteria
Itemized Fee Disclosure Before Authorization
Given the client opens the Sign‑to‑Pay step within the e‑sign packet When the payment UI loads Then the UI displays itemized lines: Base Retainer, Processing Fee(s), and Total in the firm’s currency/locale And the Total reflects the selected payment method and the firm’s fee policy And any change to payment amount or method recalculates all line items within 1 second And authorization controls remain disabled until the disclosure is visible and the client acknowledges reviewing the breakdown And the disclosure text version ID is shown adjacent to the breakdown
Fee Policy Application: Pass, Share, Absorb
Given firm fee policy is configured as Pass, Share, or Absorb with shareToClientPercent (0–100) and rounding = bankers rounding to 2 decimals When a client selects a payment method with processor-calculated fee F for base amount B Then for Pass: Client Processing Fee = F; Client Total = B + F And for Share: Client Processing Fee = round(F × shareToClientPercent/100, 2); Client Total = B + Client Processing Fee And for Absorb: Client Processing Fee = 0.00; Client Total = B And labels clearly indicate who pays the fee (e.g., “Firm absorbs” or “Client pays processing fee”)
Network & Jurisdiction Restrictions Enforcement
Given BIN/network and jurisdiction J are determined for the selected payment method When the method is debit or prepaid (or otherwise network-disallowed for surcharging) Then Client Processing Fee must equal 0.00 regardless of firm policy And the UI displays a notice “No surcharge allowed on debit/prepaid” When the computed surcharge exceeds the legal cap for J Then the surcharge is limited to the cap and the applied cap percentage is displayed When the deposit account is a trust account and J prohibits surcharging or requires fees to be paid from operating Then surcharging is disabled and fees are routed to operating per configuration And authorization is blocked with an actionable error if operating routing is not configured
Explicit Client Consent Capture
Given the fee breakdown and disclosure text are visible When the client checks “I agree to the fees and disclosures above” and proceeds to authorize Then the system records consent including: UTC timestamp, client IP, user agent, disclosure text version ID, policy applied, cap applied, and fee amounts (base, fee, total) And authorization cannot proceed unless the consent checkbox is checked
Immutable Audit Trail for Compliance
Given the client submits authorization When the transaction is finalized (success or failure) Then an append-only audit record is created with: packet ID, matter ID, jurisdiction, payment method type, masked PAN or ACH/wallet indicator, fee itemization, total, policy/cap applied, consent timestamp/IP/UA, disclosure text version, and a cryptographic hash of the disclosure+amounts And the audit record is non-editable by all roles; any correction creates a new linked record preserving the original And the audit can be exported as PDF and JSON and matches the client-visible breakdown
Real-Time Recalculation and Restriction Feedback
Given the client changes payment amount, payment method (ACH/card/wallet), or enters a card number that updates debit/credit detection When validation and BIN/jurisdiction checks complete Then fee line items and Total update within 1 second And any enforced restriction (e.g., debit no surcharge, cap applied, trust routing required) is indicated with an inline notice And the Authorize/Sign button is disabled while checks are pending or if any restriction would be violated
Smart Retainer Defaults & Editable Amounts
"As a practitioner, I want intelligent default retainers with guardrails so that I collect the right amount faster while retaining flexibility when cases vary."
Description

Auto‑suggest retainer amounts based on matter type, jurisdiction, and firm templates, with configurable minimums, maximums, and rounding rules. Allow attorneys to mark amounts as required or allow partial payments with thresholds (e.g., minimum to proceed). Support taxes or court‑specific add‑ons where applicable and pre‑fill memo/line items for trust vs. operating allocation. All defaults are overridable per matter, with changes tracked in an audit log.

Acceptance Criteria
Auto‑Suggested Retainer Based on Matter Type and Jurisdiction
Given a firm template for Matter Type = Divorce and Jurisdiction = CA suggests $3,230 with rounding mode = Nearest $50 and bounds Min = $2,000, Max = $5,000 When a new Divorce matter is created for Jurisdiction = CA and no per‑matter overrides exist Then the suggested retainer auto‑populates as $3,250 and is within $2,000–$5,000 And the suggestion source is displayed as "Template • Divorce • CA"
Configurable Min/Max and Rounding Rules Enforcement
Given firm admin configures Min = $2,000, Max = $10,000, Rounding = Nearest $50 When a template yields a pre‑rounded suggestion of $1,975 Then the displayed default amount is $2,000 (rounded to $2,000 and raised to Min) When a template yields a pre‑rounded suggestion of $10,120 Then the displayed default amount is $10,000 (capped at Max) When Rounding = Round Up to $50 and the suggestion is $3,201 Then the displayed default amount is $3,250
Manual Override with Audit Logging
Given the system presents a suggested retainer of $3,250 When an attorney edits the amount to $3,000, updates allocation to 70% trust / 30% operating, and enters Reason = "Client hardship" Then an audit entry is created capturing user id, timestamp, matter id, prior values, new values, reason, and IP And the override applies only to the current matter and does not alter firm templates And the matter history displays the change with before/after values
Required vs Partial Payment Enforcement
Given the retainer payment setting is Required in Full When a client attempts to finish e‑sign without a successful authorization for 100% of the retainer (excluding taxes/add‑ons applied) Then document completion is blocked and a clear message instructs the client to pay the full amount Given the retainer payment setting is Partial Allowed with Minimum to Proceed = $1,500 When the client pays an amount >= $1,500 Then the e‑sign packet is marked Complete and the outstanding balance is shown as due later When the client pays an amount < $1,500 Then completion is blocked with an inline error indicating the minimum required
Jurisdiction‑Aware Taxes and Court Add‑Ons
Given Jurisdiction = NY applies 4.0% sales tax on operating funds and a Court Initiation Add‑On of $45 When a suggested retainer of $3,000 is split $2,500 trust / $500 operating Then tax is calculated on the operating portion only as $20.00 and the $45 add‑on is included And the UI itemizes Base Retainer, Tax, and Court Add‑On with amounts and a correct grand total of $3,065.00 When Jurisdiction is changed to NJ with no tax/add‑on Then tax and add‑on line items are removed and totals recomputed
Trust vs Operating Allocation and Pre‑Filled Line Items
Given a firm template defines allocation = 80% trust / 20% operating and memos "Initial trust retainer" and "Administrative fee" When the suggested retainer is $3,500 Then two line items are pre‑filled: $2,800 to Trust with memo "Initial trust retainer" and $700 to Operating with memo "Administrative fee" And ledger/export mappings are set to the trust and operating accounts respectively And the sum of line items equals the suggested retainer before taxes/add‑ons
Editable Amount and Threshold Validation
Given a suggested retainer of $4,000 and Partial Allowed with Minimum to Proceed When an attorney sets Minimum to Proceed = $4,500 Then the form prevents save and displays an inline error: "Minimum to proceed cannot exceed total retainer" When an attorney sets the retainer to $900 with firm Min = $1,000 Then the form prevents save and displays an inline error referencing the firm minimum When an attorney sets the retainer to $4,040 with Rounding = Nearest $50 Then the saved amount rounds to $4,050 and the rounding action is noted next to the field
Payment‑Gated Document Finalization
"As an office manager, I want documents to finalize only after payment clears so that we avoid unpaid filings and maintain consistent intake workflows."
Description

Gate document completion on successful payment authorization according to firm policy: block final signing, watermark drafts, or hold e‑filing until funds clear. Support nuanced rules for partial payments (e.g., release engagement letter but hold court filings) and asynchronous methods like ACH (e.g., provisional hold with expiration). Emit clear statuses back to CaseSpark (Paid, Partial, Pending, Failed) and trigger downstream automations (receipt issuance, task creation, filing release) based on those states.

Acceptance Criteria
Gate Final Signature on Successful Payment Authorization
Given a signing packet has payment gating enabled per firm policy When the client attempts to finalize signing while payment status is Pending or Failed Then the final signature action is blocked, a message explains payment is required, and supported payment methods are shown And an audit log entry is recorded with block reason and current payment status When the payment provider returns authorization with status Paid for the configured amount Then the final signature becomes available within 5 seconds without requiring page reload And the audit trail captures payment ID, authorized amount, timestamp, and user context
Watermark Drafts While Payment Is Pending or Failed
Given the firm policy to watermark drafts until paid is enabled When the matter payment status is not Paid Then all previews and downloads are watermarked on every page with the text "UNPAID — NOT FINAL" at a minimum 36pt diagonal overlay and 40% opacity And any external share links only serve watermarked PDFs When the matter payment status transitions to Paid Then subsequently generated previews/downloads have no watermark and previously generated watermarked versions remain in the document history labeled as such
Hold E‑Filing Until Funds Clear Per Policy
Given the firm policy "hold e‑filing until funds clear" is enabled And the client selects ACH as the payment method When the client authorizes payment and the provider status is Pending Then the e‑filing job is queued with state "On Hold — Awaiting Funds" and is not submitted to the court And an ETA banner displays an estimated clear date based on bank timing and policy configuration When the ACH status updates to Paid within the policy hold window Then the e‑filing job auto‑releases and is submitted within 2 minutes, and the court submission receipt is attached to the matter When the ACH status updates to Failed or the hold window expires without Paid Then the e‑filing is not submitted and an alert is sent to the assigned staff member
Partial Payment Releases Engagement Letter Only
Given policy rules configure: engagement letter releases at Partial >= threshold; court filings require Paid And the retainer is $2,500 and the partial release threshold is 40% When the client pays $1,000 (40%) and status becomes Partial Then the engagement letter is unlocked for final signing and can be completed And all court‑related documents remain gated and/or watermarked per policy And the matter displays remaining balance of $1,500 with a pay link When subsequent payments bring total collected to $2,500 and status becomes Paid Then all remaining gates lift and any queued filing releases proceed automatically
ACH Provisional Hold with Expiration and Auto‑Revoke
Given the provisional hold policy is enabled with an expiration of 3 business days When the client authorizes an ACH payment and status is Pending Then a provisional hold permits engagement letter finalization but continues to block court filings And the client and staff see a countdown timer indicating time until expiration When 3 business days elapse without status Paid Then provisional permissions are revoked, watermarks re‑apply to all documents, and the client is prompted to retry payment via a fallback link And a task and email notification are sent to staff to follow up on payment
Emit Payment Statuses and Trigger Automations
Given the system receives payment provider events with statuses Paid, Partial, Pending, or Failed When any payment status changes Then CaseSpark receives a webhook within 10 seconds containing matter ID, payment ID, status, amount, method, and timestamp And the matter’s payment state is updated consistently across UI and API When the status is Paid Then a receipt PDF is generated, stored to the matter, and emailed to the client; the "Ready for Filing" task is completed; and any on‑hold e‑filing is released When the status is Partial Then a "Collect Remaining Balance" task is created with a due date 2 business days out and the client portal shows the outstanding balance with a pay link When the status is Pending Then no documents are finalized, watermarks persist, and a recheck job is scheduled every 30 minutes for up to 48 hours When the status is Failed Then signing remains blocked, the client receives a fallback pay link, and staff sees the failure reason code and message in the activity log
Fallback Pay Links & Automated Reminders
"As a paralegal, I want automatic pay links and reminders when clients don’t complete payment so that I reduce manual chasing and improve conversion."
Description

When clients skip or fail payment within the embedded flow, generate a secure, single‑use payment link tied to the same matter and envelope. Deliver links via SMS and email with one‑click resume into the correct context, and schedule automated reminders with configurable cadence until payment is completed or canceled. Include expiration controls, link invalidation on success, and analytics on delivery, opens, and conversions to optimize follow‑up.

Acceptance Criteria
Generate Single‑Use Fallback Link on Payment Skip/Failure
Given a client is in the embedded Sign‑to‑Pay flow for an active envelope When the client clicks "Skip" or a payment authorization fails Then the system generates a secure, single‑use payment link tied to the same Matter ID and Envelope ID And the link token has at least 128 bits of entropy, is HTTPS-only, and is non-enumerable And the link preserves the outstanding amount and fee disclosures at the time of generation And the link is created within 2 seconds of the skip/fail event and audit-logged with user, matter, envelope, and timestamp And if a valid fallback link already exists for the envelope Then generate a new link and immediately invalidate all prior links for that envelope
Deliver Fallback Link via SMS and Email
Given a fallback payment link has been generated When delivery is initiated Then send an email and an SMS to the primary client contact within 10 seconds And messages include firm name, matter/envelope references, amount due, and a one‑click secure link And record provider message IDs and delivery status (queued, sent, delivered, failed, bounced) for both channels And honor SMS opt‑out keywords (e.g., STOP) and email unsubscribe settings And if either email or SMS contact detail is missing or invalid Then skip that channel, record the reason, and proceed with the available channel
One‑Click Resume Into Correct Payment Context
Given a recipient clicks a valid fallback link When the link is opened Then the payment page loads in under 3 seconds and resumes the exact matter/envelope context And pre-fills the outstanding amount and shows transparent fee disclosures And presents available methods (ACH, Card, Apple/Google Pay when device/browser supports) And on successful payment capture, mark the envelope's payment gate as satisfied and proceed with post‑sign completion steps And immediately invalidate the link so it cannot be reused And if the link is expired or already used Then display a clear message and offer a one‑click path to request a fresh link
Automated Reminder Scheduling and Cadence
Given a fallback payment link was delivered and no successful payment has occurred When the configured reminder cadence is active Then schedule reminders using the firm-configured intervals (e.g., 24h, 72h) with a maximum of 5 attempts And send reminders in the client's local time zone and respect quiet hours (no sends between 8pm–8am local) And include the same secure one‑click link and current amount due And immediately stop all reminders if payment succeeds, the envelope/matter is canceled/voided, or the client opts out And expose next-send time and remaining attempts in the matter dashboard
Expiration Controls and Link Invalidation
Given a fallback link is created When the link's time‑to‑live elapses (default 7 days, configurable 1–30 days) Then the link becomes invalid and clicks route to an expiration notice with option to request a new link And any successful payment using the link marks it as used and invalidates it within 1 second And generating a new fallback link for the same envelope immediately invalidates all older links And authorized users can manually expire a link from the dashboard with a required reason code And all expiration and invalidation events are audit‑logged
Delivery, Open, and Conversion Analytics
Given fallback link communications are sent When delivery, open, and payment events occur Then capture events: link_generated, email_sent, email_delivered, email_bounced, sms_sent, sms_delivered, sms_failed, link_opened, payment_resumed, payment_succeeded, payment_failed, link_expired, link_invalidated And attach timestamps (UTC), channel, device type (where available), matter/envelope IDs, and link token ID And compute and display per‑channel conversion rates (delivered→opened→paid) at the matter and firm levels And provide CSV export and API access to the raw event data without exposing full PII in event payloads And update analytics within 60 seconds of events
Failure Handling and Fallback Flows
Given a delivery attempt fails (bounce, carrier error, rate limit) When retries are allowed Then perform up to 3 retries with exponential backoff per channel and record outcomes And if one channel fails after retries but the other is available, continue via the available channel And if both channels fail, surface an actionable alert in the matter dashboard and notify the assigned user And if client contact details are updated, offer a one‑click re‑send of the most recent valid link And ensure all failure and retry events are captured in analytics and the audit log
Trust/IOLTA Routing & Ledger Sync
"As a managing attorney, I want funds routed correctly to trust and operating with accurate ledgers so that we remain compliant and always know matter balances."
Description

Split payments between trust (IOLTA) and operating accounts according to configured allocation rules, enforcing restrictions that prohibit fees or surcharges from being drawn from trust. Create double‑entry ledger records at the matter level, reconcile processor payouts, and surface trust balances in real time. Sync transactions, refunds, and chargebacks/ACH returns to the firm’s accounting and case management records, and maintain immutable audit logs for compliance and reporting.

Acceptance Criteria
Split Routing to Trust and Operating at Sign‑to‑Pay
Given allocation rules route retainers to Trust and fees to Operating When a client completes a single Sign‑to‑Pay authorization containing both trust‑funded and fee line items Then the transaction is split into two deposits: the full trust‑funded subtotal to the Trust/IOLTA account and the fee subtotal to the Operating account Then all processor fees, surcharges, or discounts are applied only against the Operating portion; the Trust portion is deposited gross with no reduction Then the signer is shown a pre‑authorization breakdown of trust vs operating routing, amounts, and fee disclosures Then internal records and webhooks include a routing breakdown with account IDs, amounts, currency, and estimated settlement dates Then attempts to route non‑trust‑eligible items to Trust are blocked with a clear error
Enforce No Fees or Surcharges from Trust
Given a payment includes any trust‑funded line items When processor fees or card surcharges are calculated Then the system prevents any deduction of such fees from the Trust portion and posts them to Operating (expense or surcharge income) instead Then if only trust‑funded items are present, the system either adds a separate surcharge line routed to Operating (where allowed) or absorbs fees to Operating; in all cases the Trust deposit equals the trust subtotal Then configuration that allocates any fee/surcharge to Trust is blocked with a validation error and an audit event Then each transaction logs a "Trust fee‑protection: Passed" compliance flag
Matter‑Level Double‑Entry Ledgering for Split Payments
Given a split payment is successfully captured Then the system creates matter‑level double‑entry journals within 2 seconds: Then Trust: Dr Trust Bank (gross trust amount), Cr Client Trust Liability (same amount) Then Operating: Dr Operating Bank (net operating proceeds), Dr Processor Fees Expense (fees), Cr Earned Income/AR per configuration Then the sum of debits equals credits for the batch; the batch ID equals the payment ID; currency code and exchange rate are recorded Then journal entries are immutable; corrections are made via dated reversing entries only Then duplicate creation is prevented via idempotency keys; repeated webhooks do not create additional entries
Processor Payout Reconciliation (Trust and Operating)
Given processor payout reports with batch IDs are ingested hourly When a payout deposit is detected in Trust or Operating Then the system matches it to settled transactions and associated fees, marks the payout as Reconciled, and stores the processor reference Then any variance greater than $0.01 or items unmatched after 2 business days are flagged as Exception with reason codes and alerts Then partial payouts are supported and reconciliation status is tracked per payout component with a running unmatched balance Then a reconciliation report is available by date range, account, and matter showing matched, unmatched, and variances
Real‑Time Trust Balances, Holds, and Negative‑Prevention
Given a payment is authorized or captured Then the matter’s Trust Booked balance updates within 5 seconds and the Available balance excludes unsettled/held amounts until cleared Then ACH payments are labeled Pending Trust until processor confirmation; they are excluded from Available for disbursement until cleared, with an ETA displayed Then initiating trust disbursements that exceed the Available balance is blocked with an error and logged Then on ACH return or card chargeback, reversing trust journals are posted automatically, balances adjust, and any dispute/return fees are posted to Operating only
External Sync: Accounting and Case Management (Txns, Refunds, Returns)
Given accounting and case management integrations are connected When a payment, refund, chargeback, or ACH return occurs Then mapped journal entries and matter updates are pushed within 60 seconds with correct accounts, classes, tax codes, matter IDs, and contact IDs Then all sync operations are idempotent by externalRef; retries use exponential backoff up to 24 hours; failures emit alerts with correlation IDs Then refunds post reversing entries and update trust and operating balances consistently across systems Then a daily sync health report summarizes totals by type and lists any failures
Immutable Audit Log for Trust/IOLTA Compliance
Given any financial event or configuration change occurs When the event is processed Then an immutable audit log entry is written with UTC timestamp (ISO‑8601), actor, source (UI/API/Webhook), matter ID, amounts, account routing, before/after values, and a hash‑chain pointer Then audit entries are viewable/exportable by authorized roles with filters (date, user, event type, matter, amount) and exports include a verification checksum Then attempts to edit or delete audit entries are blocked; retention is at least 7 years; system time is NTP‑synchronized with drift under 500 ms

Plan Designer

Create upfront‑plus‑installment plans at send time, aligned to court dates and filing milestones. Includes automatic reminders, smart dunning with card‑to‑ACH failover, and client self‑service rescheduling within your rules—getting clients started sooner while cutting collections work.

Requirements

Milestone-Aligned Schedule Generator
"As a solo family-law attorney, I want to auto-generate payment plans tied to my case milestones so that clients’ installments align with real deadlines and reduce the risk of missed payments before key hearings."
Description

Generates payment schedules aligned to court dates and filing milestones, allowing firms to define upfront amounts and installment counts, anchor payments to specific events (e.g., filing, service, hearing), apply lead/lag offsets, and respect weekends/holidays and time zones. Supports minimum/maximum installment amounts, rounding rules, last-payment-on-date constraints, and buffers before critical hearings. Consumes matter timeline data from CaseSpark and recalculates when dates update, producing a versioned schedule with diffs for review. Exposes both UI configuration and API endpoints and validates schedules against firm rules (e.g., total, earliest start, latest end).

Acceptance Criteria
Anchor to Filing Event with Offsets, Time Zone, and Calendar Adjustments
Given a matter timeline with defined events, firm holiday calendar, buffer rules before hearings, and an account time zone And a plan definition with an upfront amount and installments anchored to a Filing event with specified day offsets When the schedule is generated Then each installment date equals the anchor event date plus its offset, adjusted by weekend/holiday rules to the next business day at 08:00 local time And no installment falls within the configured buffer window before any hearing; if an adjustment would enter the buffer, the date is moved to the nearest prior business day And the upfront payment is scheduled immediately at plan activation time
Upfront + Installment Constraints, Min/Max, and Rounding
Given a total plan amount, an upfront amount, a number of installments, minimum and maximum installment constraints, and a rounding rule (e.g., nearest $5, half-up) When the schedule is generated Then the sum of upfront plus all installment amounts equals the total plan amount And each installment amount is within the configured min/max bounds And rounding is applied per installment; any rounding residual is applied to the last installment without violating min/max And if applying the residual would violate min/max, the residual is redistributed across prior installments to satisfy constraints
Last Payment On Date Constraint Enforced
Given a last-payment-on or before constraint date and a base cadence derived from anchors and offsets When the schedule is generated Then the final installment date is on the constraint date or the nearest prior business day if the date is a weekend/holiday And intermediate installments are pulled forward as needed to respect the final date while maintaining a minimum spacing of 7 days (configurable) And if the constraint cannot be met without violating spacing or amount constraints, the schedule is marked invalid and a validation error with code LAST_PAYMENT_CONFLICT is returned
Auto-Recalculation on Timeline Update with Versioned Diffs
Given a previously accepted schedule (v1) generated from specific timeline events and anchors When any underlying timeline event date/time used by the schedule changes in CaseSpark Then a new tentative schedule version (v2) is generated using the same configuration And the system produces a diff listing changed installments with old/new dates, amounts, and reasons (e.g., AnchorMoved, BufferApplied, HolidayAdjustment) And the new version remains pending until a user reviews and accepts it; clients are not notified until acceptance And version history preserves v1 and v2 with timestamps and authors
Firm Rule Validation: Totals, Earliest Start, Latest End
Given firm-level rules for earliest allowed first payment date, latest allowed final payment date, and total amount integrity When the schedule is generated or edited Then validation passes only if the first payment is on or after the earliest start, the last payment is on or before the latest end, and the sum equals the configured total And on validation failure the UI displays inline errors and the API responds with HTTP 422 including machine-readable codes (EARLIEST_START_VIOLATION, LATEST_END_VIOLATION, TOTAL_MISMATCH) and offending installment indices And invalid schedules cannot be saved or activated
REST API: Deterministic Generation and Idempotency
Given a POST to /v1/payment-schedules with a complete plan definition, anchors, offsets, rounding rules, constraints, and an idempotency key When the same request is submitted multiple times with the same idempotency key Then the service returns HTTP 201 on first request and 200 on subsequent requests with the same schedule_id and identical schedule content And all dates are returned in ISO 8601 with explicit time zones; weekend/holiday and buffer adjustments are reflected in metadata per installment And error responses use standard HTTP codes (400/401/403/404/409/422) with stable error codes and messages
UI Plan Designer: Interactive Configuration and Preview
Given a user opens the Plan Designer for a matter When they configure upfront amount, installment count, anchors, lead/lag offsets, min/max installment amounts, rounding rules, buffer windows, and last-payment constraints Then the preview updates in real time to show installment dates and amounts with badges for adjustments (Weekend, Holiday, Buffer) And inline validations prevent saving when constraints are violated, with tooltips explaining required fixes And saving persists the configuration and creates a versioned schedule (v1) available for review
Send-Time Plan Composer & Template Library
"As a two-attorney practice manager, I want to build and attach a payment plan when sending engagement documents so that clients can sign and enroll in autopay in one step."
Description

Embeds a plan composer into the send flow to assemble upfront-plus-installment terms from fee items at the moment documents are sent for e-sign, enabling selection of firm-approved templates (e.g., Standard 30/60/90), preview of schedule and totals, and one-click attachment of plan terms to the engagement packet. Calculates taxes/surcharges/discounts, checks against minimum retainer policies, and generates payment authorization clauses in the e-sign packet. Supports overrides with audit notes, saves selected template per matter, and requires validation before sending (e.g., payment method required, amounts sum to total).

Acceptance Criteria
Template Selection and Real-Time Schedule Preview at Send Time
Given I am in the Send flow with one or more fee items on the matter When I select a firm-approved plan template (e.g., Standard 30/60/90) Then the composer distributes fees into an upfront amount and installments per the template’s rules And the schedule shows installment count, due dates, and amounts aligned to selected court dates/milestones And subtotals, taxes, surcharges, discounts, and the grand total are displayed And the sum of upfront plus installments equals the grand total with currency rounding to 2 decimals
Validation Gate: Send Disabled Until Plan Balanced and Required Inputs Present
Given the plan composer is open When any validation fails (amounts do not sum, negative values, missing payment method, invalid due dates, minimum retainer violation) Then the Send button is disabled and inline, field-level errors identify each issue And the first error is focused for accessibility When all validations pass Then the Send button is enabled and the validations re-run on click prior to sending
Minimum Retainer Policy Enforcement with Override and Audit
Given firm minimum retainer policies are configured When the computed upfront amount is below the policy threshold Then a blocking alert explains the violation and shows the required minimum And users with override permission can override by entering an audit note (min 10 characters) and confirming And the system logs user ID, timestamp, original upfront, new upfront, policy threshold, and free-text reason to the matter’s audit log And users without permission cannot send until the upfront meets or exceeds the minimum
One-Click Attach Plan Terms and Generate Payment Authorization Clauses
Given a plan has been composed When I click Attach Plan Terms to Engagement Packet Then a Plan Terms document is generated and appended to the e-sign packet And it includes the itemized schedule, totals, taxes/surcharges/discounts, late/NSF fees per policy, and cancellation terms And payment authorization clauses enumerate amounts, schedule, permitted methods (card and ACH), and ACH/card fallback consent And the e-sign packet contains required signature/initial fields bound to these clauses And the final packet preview matches the generated terms 1:1 And the attached document is stored with the matter and is immutable once sent
Jurisdiction-Aware Taxes/Surcharges/Discounts Calculation
Given the matter’s jurisdiction is set and tax/surcharge/discount rules exist When I compose a plan Then applicable taxes and surcharges are computed per jurisdiction and fee-item taxability And discounts are applied once, in the configured order, before tax if configured as pre-tax And a line-level breakdown of each component is visible on hover or expand And recalculation occurs in under 300 ms after any change to items, template, or jurisdiction And if jurisdiction is missing, I am prompted to set it and sending is blocked
Template Library Governance and Persistence Per Matter
Given a library of firm-approved templates exists When I open the plan composer at send time Then only approved templates are displayed with name, description, and key rules And the default template is preselected by matter type if configured When I select a template and send Then the selected template ID and version are saved to the matter And changing the template later recomputes the schedule and logs the change in the audit log And removing a template from the library does not alter previously attached plan terms And updating a template does not change existing matters unless the user explicitly reapplies the new version
Payment Method Vaulting & Autopay Enrollment
"As an attorney, I want clients to enroll a primary and backup payment method when they sign so that payments run automatically without follow-up."
Description

Captures and securely vaults client payment methods (card and ACH) during e-sign, enrolling the selected method for autopay per schedule with optional backup method capture. Supports PCI-compliant tokenization, ACH verification (micro-deposits or instant verification), and firm-configurable rules for allowed methods and backup requirements. Associates tokens to the matter and plan, stores last4/brand only, and provides firm-side visibility without sensitive data. Ensures consent text and authorization are included and time-stamped, and links to the plan version for dispute defense.

Acceptance Criteria
Card Vaulting and Autopay Enrollment at E‑Sign
Given a client opens the e‑sign package for a payment plan that allows cards When the client enters a valid card and completes e‑sign Then the card is tokenized via a PCI‑compliant gateway and no PAN is stored by CaseSpark And the token is associated to the specific matter and plan And autopay is scheduled per the plan start date and cadence And only card brand and last4 are stored and displayed to firm users And the initial payment (if required by plan) is authorized/captured and a receipt is generated
ACH Verification and Deferred Autopay Activation
Given the plan allows ACH and firm rules enable instant verification and micro‑deposits When the client completes instant account verification Then an ACH token is created and autopay status is set to Active immediately Given the client selects micro‑deposit verification instead When the micro‑deposit amounts are posted and the client confirms them within the firm‑configured verification window Then the ACH token is verified and autopay status transitions from Pending to Active And if not confirmed within the configured window, autopay enrollment is canceled and both client and firm are notified
Backup Method Capture and Automated Failover
Given firm rules require a backup payment method When the client provides both a primary and a backup method during e‑sign Then the system validates the methods are distinct and vaults both tokens And the plan attempts the primary method per the firm‑configured dunning policy (max retries and spacing) And upon final primary failure, the system automatically attempts the backup within the firm‑configured window and records failover reason and outcome And the client is notified prior to the backup charge per notification settings And if the backup also fails, the plan status becomes Delinquent and a task is created for staff follow‑up
Consent, Authorization, and Plan Version Linkage
Given the client is enrolling in autopay during e‑sign When consent text and an authorization checkbox are presented as required Then e‑sign completion is blocked until authorization is explicitly accepted And the signed consent text, plan version identifier/hash, timestamp, client IP, and user agent are recorded immutably And an audit record links the payment tokens and charges to the exact plan version for dispute defense And firm users can retrieve the consent record without exposing full payment data
Matter/Plan Association and Masked Firm Visibility
Given a firm user with appropriate permissions views the matter's billing section When a plan with vaulted payment methods exists Then the user can see method type, brand, last4, token status (Active/Pending), and next scheduled charge And full PAN/account/routing numbers and raw tokens are never visible or retrievable And only users with Billing‑Manage role can remove, replace, or change autopay enrollment And removing a token preserves historical references but disables future charges
Firm‑Configurable Allowed Methods and Enforcement
Given a firm admin configures allowed payment methods and backup requirements for a plan template When a plan is sent for e‑sign using that template Then the client is only offered the allowed payment methods And if a backup method is required, the flow cannot be completed until a valid backup is provided and vaulted And changes to these settings are audited with user and timestamp and apply to new plan sends only
Resilience and Error Handling for Tokenization/Verification
Given a transient error occurs during tokenization or account verification When the client submits payment details Then the system retries idempotently up to the firm‑configured retry count with exponential backoff And upon final failure, a clear non‑sensitive error is shown to the client with next‑step guidance And no raw payment data appears in application or infrastructure logs And monitoring emits alerts when failures exceed the configured threshold within a 1‑hour window
Smart Dunning with Card-to-ACH Failover
"As a practice owner, I want failed payments to be retried intelligently with automatic failover to another method so that cash flow is protected without manual collections work."
Description

Implements a rules-driven dunning engine that categorizes declines, retries on optimal schedules, and automatically fails over from card to ACH (or vice versa) when a primary method fails, subject to client authorization and firm policy. Triggers immediate client prompts to add or verify a backup method when none exists, escalates based on risk (e.g., near-hearing), and pauses retries on hard declines. Provides firm-configurable retry windows, max attempts, and lockouts, and logs all attempts and outcomes for compliance.

Acceptance Criteria
Soft Decline Retry Scheduling
Given a scheduled installment charge fails with a soft-decline reason mapped by the system And firm policy defines a retry window of X hours/days, a minimum interval of Y hours, a maximum of N retries, and preferred retry hours in the client’s timezone When the dunning engine schedules subsequent attempts Then retries are scheduled only within the defined window and preferred hours And the time between any two retries is at least the configured minimum interval And the total number of retries for this installment does not exceed the configured maximum And a lockout state is applied after the maximum is reached until the next installment date or manual reset, per policy
Hard Decline Pause and Notification
Given a payment attempt returns a hard-decline category based on the firm’s decline-code mapping (e.g., do-not-retry, invalid account) When the decline is received Then all automatic retries for that payment instrument on this plan are immediately paused And the plan’s collection status is set to “payment method required” And the client and assigned firm user(s) are notified through configured channels with the mapped reason And no further attempts occur until a new verified method is added or a user applies a manual override, both of which are logged
Automatic Card-to-ACH (and ACH-to-Card) Failover with Consent
Given the primary method fails with a soft-decline and an alternate verified method exists (card or ACH) And the firm’s policy allows automatic failover after K failed attempts on the primary method And the client’s authorization on file permits cross-method failover When the next attempt is due Then the engine uses the verified alternate method for the charge And the charge respects method-specific rules (e.g., ACH only on banking days, card velocity limits) And the system records the consent artifact ID, policy version, and method used in the audit log And the client receives a confirmation that identifies the method used and the amount And if the alternate method is not verified, the engine does not fail over and instead triggers the backup-method prompt workflow
Risk-Based Escalation Near Hearing Date
Given an installment is overdue and the linked matter has a hearing within Y days per matter metadata And the balance due > 0 When a decline occurs or remaining retries <= the policy’s escalation threshold Then the engine elevates the dunning tier per policy (e.g., increases notification frequency, adds additional channels) And notifies the assigned attorney/staff immediately And requires manual approval before pausing the plan or closing collections while within the Y-day window And all escalated actions and approvals are captured in the audit log with timestamps
No Backup Method — Immediate Client Prompt
Given a payment attempt fails and no verified backup payment method exists on the plan When the decline is received Then the client is immediately prompted via the firm’s configured channels (e.g., SMS and email) to add or verify a backup method And the prompt includes a secure, single-use link that expires after T hours And the system tracks delivery status and click-through for each channel And upon successful addition and verification of a backup method, the engine re-queues a charge per current policy And if no action is taken within T hours, up to M reminder prompts are sent at the configured cadence
Firm-Configurable Dunning Policies
Given an admin updates dunning settings (retry windows, minimum intervals, max attempts, lockout duration, failover rules, escalation thresholds) When the settings are saved Then inputs are validated against allowed ranges and dependencies (e.g., minimum interval < retry window) And the change is versioned with timestamp, admin identity, and a change summary And the new version applies to newly scheduled attempts while in-flight schedules remain unchanged unless “apply now” is selected And a policy preview displays the next three projected attempt times for a sample installment in a selected timezone
End-to-End Compliance Logging
Given any dunning-related event occurs (attempt, retry, decline, category mapping, failover, pause, escalation, notification, policy change) When the event is processed Then an immutable log entry is stored containing: UTC timestamp, actor (system/user), installment ID, payment method type and fingerprint, attempt count, raw processor code, mapped decline category, policy version, next scheduled action (if any), notification IDs, and outcome And logs are filterable by client, matter, date range, and outcome And logs are exportable in CSV within the last 24 months with pagination and rate limits And exported logs match on-screen records 1:1 for sampled entries
Automated Reminder Orchestration
"As a busy attorney, I want automatic payment reminders sent with the right timing and content so that clients pay on time without staff intervention."
Description

Schedules and delivers multi-channel reminders (email/SMS) before due dates, on due dates, and post‑due, using templates with merge fields and matter context. Supports quiet hours, localized send times by client time zone, opt-out management, and deliverability tracking (opens, bounces). Includes smart links to a client portal for pay-now, rescheduling (if allowed), and method updates. Coordinates with dunning to avoid redundant messages and updates content based on current plan status.

Acceptance Criteria
Pre-Due Multi-Channel Reminder Scheduling
Given a payment plan with an installment due at D and email+SMS enabled When the plan is activated Then the system schedules pre-due reminders at configured offsets (e.g., D-7, D-3, D-1) in the client’s local time and persists the schedule within 60 seconds And each scheduled send respects quiet hours by moving to the next allowed window prior to D And no more than the configured maximum pre-due reminders (default 3) are scheduled per installment And all scheduled jobs are visible in the plan/matter activity timeline with channel, send time, and template name
Due-Date Reminder With Smart Links
Given an installment with due date/time D in time zone T When the due-date reminder is sent Then the message renders using the selected template with merge fields: {client_first_name}, {matter_name}, {installment_amount}, {due_datetime_local}, {plan_name}, {installment_number} And the email and SMS include a one-click secure smart link that deep-links to the client portal and expires after 7 days or on first use And clicking the link opens the pay-now screen and records a click event within 60 seconds And, if allowed by plan rules, the same link provides access to rescheduling and payment method update flows And message send time occurs within the client’s local day and outside quiet hours
Post-Due Reminder And Dunning Coordination
Given an installment is past due by at least 1 day When a post-due reminder is eligible to send Then if a dunning message is scheduled within the next 2 hours or was sent in the last 24 hours, the post-due reminder is suppressed And otherwise send at most one post-due reminder per 24 hours up to the configured limit (default 3) And if a payment is posted or a promise-to-pay is recorded before send time, cancel pending post-due reminders for that installment And post-due content reflects current past-due amount and aging bucket And all suppressions and sends are logged with reason codes
Quiet Hours And Localized Send Times
Given practice quiet hours are 21:00–08:00 local and the client has time zone T When any reminder’s calculated send time falls within quiet hours Then the send is deferred to 08:00 T on the next allowed day prior to the due date or to the next allowed window for post-due messages And all sends use IANA time zone rules and correctly handle DST transitions And if client time zone is unknown, infer from profile/contact data; if still unknown, use the practice default time zone And every deferral is recorded with original and adjusted timestamps
Opt-Out Management And Channel Suppression
Given a client replies STOP to an SMS reminder or sends an equivalent carrier-recognized keyword When any future SMS reminder would be sent to that client Then it is suppressed and the opt-out is recorded within 60 seconds, with a confirmation SMS where allowed And given a client clicks an email unsubscribe link for reminders Then email reminders to that address are suppressed for that client and matter, with re-subscribe options provided (START/HELP for SMS; link for email) And opt-out preferences are enforced per channel and honored across all plans for the client And suppression events are visible in the activity timeline
Deliverability And Engagement Tracking
Given reminders are sent via email and SMS When provider events occur Then deliveries, opens (email), clicks (both), bounces (email), failures (SMS), and unsubscribes are captured and attributed to the reminder within 5 minutes And hard bounces suppress future email to that address until updated; soft bounces are retried up to 3 times with exponential backoff And metrics are viewable per reminder and aggregated per installment and plan And all events retain message template, channel, timestamp, and provider response
Plan Status–Driven Content And Auto-Cancellation
Given a reminder is scheduled for a future time When the plan or installment status changes to paid, canceled, paused, or rescheduled before send time Then the reminder is re-evaluated at send time: paid/canceled reminders are auto-canceled; paused reminders are deferred; rescheduled reminders re-render with updated amounts and dates And cancellations/deferrals occur within 60 seconds of the status change when the send is within the next 24 hours And the final sent content always reflects the current plan status and installment details at send time And all re-evaluations are audited with before/after values
Client Self-Service Rescheduling with Guardrails
"As a client, I want to adjust an installment date within limits so that I can stay current without calling the office."
Description

Enables clients to propose or select new installment dates within firm-defined rules (e.g., max number of changes, max deferral days, cannot push past final hearing, minimum gap between payments). Presents real-time impact on schedule and final date, recalculates amounts if necessary, and updates reminders accordingly. Supports optional firm approval workflows, generates updated plan versions and authorizations, and records a full audit trail of changes with timestamps and IP addresses.

Acceptance Criteria
Guardrails Validation on Date Selection
Given a client is authenticated via a secure reschedule link for plan P with installments on 2025-10-01, 2025-10-15, 2025-11-01 And firm rules: max deferral days = 21; minimum gap between payments = 14 days; cannot schedule past final hearing date = 2025-12-20 When the client selects a new date 2025-10-18 for the 2025-10-15 installment Then the selection is accepted without validation error And the Confirm Reschedule action is enabled When the client selects a new date 2025-12-25 for any installment Then a validation error "Cannot schedule after final hearing date (2025-12-20)" is shown and Confirm Reschedule is disabled When the client selects a date that makes the gap to an adjacent payment < 14 days Then a validation error "Minimum gap between payments is 14 days" is shown and the date is rejected When the client attempts to defer an installment by more than 21 days Then a validation error "Maximum deferral is 21 days" is shown and the date is rejected
Enforce Maximum Reschedule Count
Given plan P tracks client reschedule count with firm rule max changes = 2 per plan And current reschedule count = 1 When the client submits a valid reschedule Then the reschedule succeeds and the reschedule count increments to 2 Given current reschedule count = 2 When the client attempts another reschedule Then the reschedule UI displays "Reschedule limit reached" and selection controls are disabled And any API attempt returns HTTP 422 with error code RESCHEDULE_LIMIT_REACHED
Real-Time Schedule Preview and Amount Recalculation
Given firm rule "Maintain equal installments after reschedule" is enabled And remaining balance = $900.00 across 3 installments on 2025-10-15, 2025-11-15, 2025-12-15 When the client moves the 2025-11-15 installment to 2025-11-29 within guardrails Then the preview updates in under 300 ms to show the new dates and the final installment date recalculated if impacted And the preview displays a before/after diff for all changed installments And per-installment amounts are recalculated to keep total = $900.00 with rounding to 2 decimals and any remainder <= $0.01 applied to the last installment And no installment amount falls below firm minimum installment amount if configured
Reminder Schedule Rebuild After Reschedule
Given reminder policy: email and SMS at T-7d, T-3d, T-1d 09:00 local time and T-0d 08:00 local time And an installment originally scheduled for 2025-10-15 has upcoming reminders When the client confirms moving it to 2025-10-29 Then all future reminders tied to the original date are canceled And new reminders are scheduled for 2025-10-22 09:00, 2025-10-26 09:00, 2025-10-28 09:00, 2025-10-29 08:00 in the client's local time zone And no duplicate reminders exist for the same timestamp and channel And reminder content reflects the new date and amount And opt-out preferences and channel availability are respected
Conditional Firm Approval Flow
Given firm rule "Require approval if deferral > 7 days" is enabled And the client proposes moving 2025-10-15 to 2025-10-25 (10-day deferral) When the client submits the proposal Then the change enters Pending Firm Approval and no schedule or reminders are modified And the firm receives an in-app task and an email notification within 1 minute When a firm user approves within 2 business days Then the change is applied, reminders are rebuilt, and the client receives an approval notification When a firm user rejects or 2 business days elapse without action Then the change is not applied and the client receives a rejection or expiration notification
Plan Versioning and Authorization Capture
Given firm rule "Require e-sign authorization on material changes" is enabled (material = date shift > 7 days or amount change > $0.00) And a reschedule is approved (if required) and ready to apply When the system processes the reschedule Then a draft plan version vN+1 is created capturing new dates, amounts, and terms And an updated authorization document referencing vN+1 is generated And the client is prompted to e-sign; no schedule or reminder changes take effect until e-sign is completed When the client e-signs the authorization Then the authorization is stored in the matter with timestamp and document ID, and vN+1 becomes Active and applied When the client does not e-sign within 48 hours Then the draft expires, no changes are applied, and both client and firm are notified
Immutable Audit Trail with IP and Timestamps
Given audit logging is enabled for plan P When the client submits a reschedule request from IP 203.0.113.10 and user agent UA-1 And the change is evaluated, approved, versioned, authorized, and applied Then the audit log records events: RequestCreated, RuleEvaluated, ApprovalGranted/Rejected, PlanVersionCreated, AuthorizationSigned, ScheduleApplied And each entry includes UTC timestamp to the second, actor identity (client or firm user), source IP address, user agent, and before→after diffs for all changed dates and amounts And the audit trail is immutable, visible in the matter timeline, exportable as CSV, and each event references the plan version ID And audit entry creation succeeds even if downstream notifications fail
IOLTA/Trust and Fee Allocation Compliance
"As a family-law attorney, I want payment plans to respect trust accounting rules so that retainers and earned fees are handled compliantly without extra bookkeeping."
Description

Allocates upfront and installment payments between trust (IOLTA) and operating accounts per firm rules and matter type, ensuring retainers are deposited to trust and earned fees are transferred appropriately. Supports split payments, ledger mapping, and exports/sync to accounting systems (e.g., QuickBooks) with detailed entries. Prevents overdrawing trust balances, maintains reconciliation reports, and preserves immutable logs for audits. Reflects allocations in client receipts and the engagement agreement.

Acceptance Criteria
Rule-Driven Allocation for Upfront Retainer and Installments
Given firm allocation rules by matter type and line-item tags (Retainer, Earned Fee, Cost) When an upfront-plus-installment plan is created and the first payment is processed Then retainer-designated amounts are deposited to the designated IOLTA trust account and earned-fee-designated amounts are deposited to the operating account And Then the client ledger reflects separate trust and operating entries with correct matter, plan ID, and line-item references And Then the receipt itemizes allocations by account (Trust vs Operating) and shows the updated client trust balance
Split Payments and Card-to-ACH Failover Allocation
Given a payment split across multiple methods (e.g., card + ACH) for a single plan installment When one method fails and the system retries using card-to-ACH failover Then the final successful transactions are allocated to trust and operating per rules without duplicate deposits or double-counted ledger entries And Then a single consolidated receipt shows all successful payment parts and their allocations; failed attempts are logged but not posted to ledgers And Then dunning status and next attempt times update according to firm rules
Trust Overdraft Prevention on Earned Fee Transfers
Given an invoice is marked earned and a trust-to-operating transfer is scheduled from the client's trust ledger When the available client trust balance is less than the transfer amount Then the transfer is blocked, no partial or negative balance is created, and the user is notified with the reason And Then the blocked event is recorded in the immutable audit log with user/action/time and correlation to the matter and plan And Then no ledger movement occurs until sufficient funds exist
Ledger Mapping and QuickBooks Sync for Trust/Operating
Given QuickBooks sync is enabled and account mapping for Trust Bank, Client Trust Liability, Operating Bank, and income accounts is configured When a plan payment and any subsequent earned-fee transfer are posted Then the sync creates entries with correct accounts, customer:matter, class/location (if used), and memo including plan ID and installment number And Then trust deposits map to Debit: Trust Bank, Credit: Client Trust Liability; earned-fee transfers reduce Client Trust Liability and increase Operating Bank and mapped income per firm rules And Then repeated sync runs are idempotent with no duplicate entries; failures surface with error messages and do not partially post
Three-Way Reconciliation and Immutable Audit Log
Given trust transactions exist for the period When a reconciliation report is generated Then the report provides three-way reconciliation: bank balance, client ledger balance, and trust liability account balance match, with itemized outstanding entries and beginning/ending balances And Then every trust-related event (deposit, transfer, block, refund, edit attempt) is recorded in an append-only audit log with timestamp (UTC), actor, before/after values, and hash linkage And Then audit logs are viewable, exportable (CSV/JSON), and cannot be altered or deleted by any role
Client-Facing Receipts and Engagement Agreement Allocation Disclosures
Given a plan is sent for acceptance and first payment is completed When the client views the receipt and engagement agreement Then both documents label amounts allocated to Trust (Retainer) and Operating (Earned Fees/Costs), show remaining trust balance, and list the schedule of future installments with dates and amounts And Then totals match posted ledger entries to the cent; documents are stored with immutable references for audit
Client Self-Service Rescheduling Preserves Trust Compliance
Given firm-defined rescheduling rules (windows, max deferrals) and allocation rules When a client reschedules a future installment within allowed parameters Then allocation targets (Trust vs Operating) remain unchanged and the next collection date updates without triggering any transfers from trust to operating prior to fees being marked earned And Then the updated schedule appears in the plan, client receipt history, and reconciliation projections; all changes are logged immutably

Auto Replenish

Maintains minimum trust balances with configurable thresholds. When funds dip, it auto‑requests top‑ups (or auto‑charges with prior consent), sending one‑tap SMS/email links and pausing non‑critical steps if balances are insufficient—preventing filing delays and smoothing cash flow.

Requirements

Configurable Trust Thresholds & Replenishment Rules
"As a firm admin, I want to set per-matter trust balance thresholds and automatic top-up rules so that funds are available before filings and we avoid delays and cash flow gaps."
Description

Provide firm-wide defaults and per-matter overrides for minimum trust balances and target top-up amounts. Allow configuration of trigger thresholds (absolute dollar or percentage), replenishment targets (to-threshold, buffer, or fixed), minimum/maximum charge amounts, and frequency windows (immediate, business-hours-only, or scheduled). Support payment method preference ordering (ACH first, then card), weekend/holiday handling, client-specific quiet hours, and jurisdiction-aware pre-funding rules before filings. Include preview/simulation of upcoming replenishments, validation to prevent conflicting rules, and audit of configuration changes. Expose settings via admin UI and API for automation and templating across practice areas.

Acceptance Criteria
Firm-Wide Defaults and Per-Matter Overrides
- Given a firm has defaults min_balance=$500 and target_top_up=$800 When a new matter is created without overrides Then the matter inherits min_balance=$500 and target_top_up=$800. - Given a matter has overrides min_balance=$750 and target_top_up=$1000 When the firm updates defaults Then the matter retains its override values. - Given an authorized admin When updating defaults via Admin UI Then the change is saved, versioned, and an audit log entry records who, when, and the before/after values. - Given a valid API token When GET /v1/trust-replenishment/settings is called Then the response contains the current firm defaults and override flags with 200 OK. - Given a practice area template with defined thresholds When the template is applied on matter creation Then those values pre-populate the matter’s overrides.
Threshold Triggers: Absolute Dollar or Percentage
- Given trigger_type=absolute and trigger_value=500 When current_trust_balance drops below 500.00 Then a replenishment event is queued within 60 seconds. - Given trigger_type=percentage and trigger_value=40 and target_top_up_amount=1000 When current_trust_balance is less than 400.00 Then a replenishment event is queued; When it is 400.00 or more Then no event is queued. - Given trigger_type=percentage When trigger_value is outside 1–100 inclusive Then validation prevents save and returns an error message. - Given a matter configuration When both absolute and percentage trigger types are selected Then validation blocks save with a single clear error indicating only one trigger type may be active.
Replenishment Target Strategies: To-Threshold, Buffer, Fixed
- Given target_strategy=to_threshold and threshold=500 and current_trust_balance=320 When a replenishment executes Then charge_amount equals 180. - Given target_strategy=buffer and threshold=500 and buffer_amount=200 and current_trust_balance=320 When a replenishment executes Then charge_amount equals 380. - Given target_strategy=fixed and fixed_amount=350 and current_trust_balance=320 When a replenishment executes Then charge_amount equals 350. - Given any target_strategy When calculated charge_amount would be <= 0 Then no charge is attempted and the event is marked as no-op. - Given currency is USD When amounts are computed Then rounding is to the nearest cent using bankers’ rounding.
Charge Constraints and Scheduling Windows
- Given min_charge=50 and max_charge=1000 and calculated_charge=30 When a replenishment executes Then the charge_amount is clamped to 50 and result flagged as min_adjusted. - Given min_charge=50 and max_charge=1000 and calculated_charge=3000 When a replenishment executes Then the charge_amount is clamped to 1000 and result flagged as max_capped. - Given window=immediate and allowed_now=true When a trigger fires Then the charge is attempted immediately. - Given window=business_hours_only and the firm hours are 09:00–17:00 in the firm timezone When a trigger fires at 19:30 local time Then the charge is scheduled for 09:00 next business day. - Given window=scheduled and schedule_time=2025-09-15T10:00 in firm timezone When a trigger fires Then the charge is queued for that time unless blocked by quiet hours. - Given day is weekend or recognized firm holiday and window=business_hours_only When a trigger fires Then the charge is scheduled for 09:00 on the next business day. - Given client quiet_hours=21:00–07:00 in client timezone When a charge would occur during quiet hours Then no auto-charge or notification is sent and the event is deferred to the next allowed window.
Payment Method Preference Ordering and Consent
- Given preference_order=[ACH, CARD] and client has valid ACH mandate When a charge executes Then ACH is attempted first. - Given ACH attempt fails with a retryable error and CARD is available When a charge executes Then the system retries via CARD within the same event and records the fallback. - Given no stored payment method has auto-charge consent When a charge should execute Then no auto-charge occurs and a one-tap payment request is sent via SMS/email instead. - Given a matter-specific payment preference override exists When a charge executes Then the override order is used for that matter. - Given any charge attempt When completed Then the outcome, method used, authorization id, and timestamp are stored and appear in the audit log.
Jurisdiction-Aware Pre-Funding Rules
- Given jurisdiction=CA-LA and pre_funding_rule requires $435 filing fee before submission When a filing step is initiated with balance <$435 Then the system blocks the filing step and creates a replenishment event to reach the required amount per configured strategy. - Given jurisdiction has no defined pre_funding_rule When a filing step is initiated Then firm defaults are applied. - Given a matter changes jurisdiction from X to Y with different pre-funding amounts When saved Then subsequent replenishments and gating checks use Y’s rules. - Given business_hours_only is configured and the next allowed window is after the filing deadline When a filing step is initiated Then the system surfaces a warning and presents a one-tap request option to the client immediately.
Simulation, Conflict Validation, Audit Trail, and API Exposure
- Given a user selects “Preview Upcoming Replenishments” with horizon=14 days When executed Then the system displays predicted dates, amounts, and methods for each matter, based on current balances and rules. - Given a matter and schedule_time=2025-09-15T10:00 with business_hours_only=true and client quiet_hours=09:30–11:00 When saving settings Then validation flags the conflict and requires user resolution before save. - Given min_charge=500 and max_charge=400 When saving settings Then save is blocked with an error “min_charge must be <= max_charge”. - Given an admin changes any replenishment setting When saved Then an audit entry captures user id, timestamp, entity (firm/matter/template), and before/after JSON. - Given API client sends PUT /v1/trust-replenishment/settings with a valid template payload and If-None-Match header When processed Then the operation is idempotent and returns 200 with the stored configuration. - Given GET /v1/trust-replenishment/templates?practice_area=Family When called with valid auth Then it returns the available templates with pagination metadata.
Consent Capture & Payment Method Tokenization
"As a client, I want to securely authorize automatic trust top-ups with clear limits so that my attorney can proceed without repeated payment requests."
Description

Capture explicit client consent for automatic trust replenishments with configurable limits (per-transaction cap, daily/monthly caps) and revocation options. Present clear terms during intake or via secure portal, record e-signed authorization with timestamp, IP, and document hash, and store consent linked to client-matter. Tokenize payment methods through PCI-compliant processors; support ACH (with verification/micro-deposits or instant verification) and cards (3DS/SCA where required). Allow multiple on-file methods with priority ordering and per-method limits. Provide consent lifecycle management, audit trail, and notifications upon consent changes. Do not store raw PAN or bank details on CaseSpark servers; rely on processor tokens and vault.

Acceptance Criteria
Intake Consent Capture with Caps and E‑Signature
Given a client in the intake portal on the Auto Replenish consent step, When the step loads, Then the terms display the charge authorization, per‑transaction cap, daily cap, monthly cap, frequency, revocation method, and payment methods that may be used. Given the consent form, When the client has not checked the explicit consent checkbox or provided a signature (typed or drawn), Then the Agree/Continue action is disabled and inline validation messages are shown. Given the consent form, When any cap value is missing or invalid (non‑numeric, negative, or zero), Then submission is blocked with an error specifying the field to correct. Given the client agrees, signs, and submits, When submission succeeds, Then an authorization record is created with client ID, matter ID, terms version ID, timestamp (UTC), IP address, user agent fingerprint, signature image/hash, and SHA‑256 hash of the rendered authorization PDF. Given a successful authorization record, When staff views the matter’s Billing > Consents, Then the consent appears linked to the client‑matter and is downloadable as an evidence package. Given firm‑level default caps exist, When the client does not modify caps, Then the default caps are saved on the consent record and displayed.
Card Method Tokenization with 3DS/SCA
Given the Add Card form, When it renders, Then card number and CVV fields are processor‑hosted (iframe) and not native CaseSpark inputs. Given a card subject to SCA, When the client submits, Then a 3DS challenge is invoked by the processor; on success a token is returned and saved; on failure no token is saved and an error is shown. Given successful tokenization, When viewing Payment Methods, Then the card is shown as brand + last4 + expiry only, with no full PAN/CVV stored or displayed. Given a saved card token, When viewing the audit log for the matter, Then an entry exists showing timestamp, actor, token reference (redacted), brand, last4, and 3DS outcome (frictionless/challenged/succeeded/failed). Given a processor decline or risk block, When the client submits the card, Then no token is stored and the UI shows the processor’s decline reason (mapped to user‑friendly text).
ACH Setup via Instant Verification or Micro‑Deposits
Given the Add Bank Account flow, When the client selects Instant Verification, Then they complete the processor’s bank‑link flow; on success a bank token is saved; on cancel or failure no token is saved and the UI prompts to retry or switch to micro‑deposits. Given the Add Bank Account flow, When the client selects Micro‑Deposits, Then two deposits are initiated and the method status is Pending Verification and is not usable for charges. Given a Pending Verification ACH method, When the client enters the two correct deposit amounts within 10 calendar days, Then the method status updates to Verified and the token becomes usable. Given a Pending Verification ACH method, When the client enters incorrect amounts three times, Then verification locks, the method remains unusable, and staff can re‑initiate deposits. Given a verified ACH token, When viewing Payment Methods, Then the bank is displayed masked (bank name if available + account type + last4) and can be assigned priority and per‑method limits. Given ACH setup actions, When viewing the audit trail, Then entries include timestamp, actor, verification method (instant/micro‑deposits), status changes, and masked identifiers.
Auto‑Replenish Execution Enforcing Consent Caps and Method Priority
Given an active consent with caps and at least one tokenized method, When the trust balance drops below the configured threshold, Then Auto Replenish selects the highest‑priority method that has remaining daily/monthly allowance and whose per‑transaction cap is not exceeded by the recharge amount. Given the required top‑up exceeds the per‑transaction cap of the selected method but daily/monthly caps allow multiple charges, When Auto Replenish runs, Then it splits into multiple charges that each do not exceed the per‑transaction cap until the target is met or caps are reached. Given all methods have reached their daily/monthly caps or a charge is declined, When Auto Replenish cannot fulfill the target, Then non‑critical workflow steps are paused, and the client receives SMS/email with a one‑tap payment link to complete funding. Given Auto Replenish transactions process, When they succeed, Then receipts are logged, the trust balance updates, and audit entries link each charge to the consent record used. Given Auto Replenish selects a method, When that method has a per‑method limit lower than the requested amount, Then the system respects the limit and does not attempt a higher amount.
Consent Revocation, Update, and Effective Suspension
Given an active consent, When the client revokes in the portal or staff records revocation, Then Auto Replenish is immediately disabled for that client‑matter and scheduled charges are canceled. Given a consent is revoked, When any Auto Replenish trigger occurs, Then no charges are attempted and the system logs “Consent Revoked” as the reason. Given a consent is revoked or updated (caps, priority of methods, per‑method limits), When the change is saved, Then the client and assigned staff receive notifications (email and in‑app), and the consent record stores old and new values with timestamp, actor, and change reason. Given a revoked consent, When the client provides new authorization, Then a new consent record is created with a new terms version and is not merged with the revoked record.
Audit Trail and Evidence Package for Consent Lifecycle
Given any consent creation, update, or revocation, When viewing the matter’s Audit Trail, Then entries include timestamp (UTC), actor (client/staff/service), IP, user agent fingerprint, terms version, document hash, and a pointer to the signed artifact. Given a consent record, When exporting the evidence package, Then the export includes the rendered authorization PDF, the signature certificate, the SHA‑256 document hash, the event timeline, and the payment method token references (redacted), and the export succeeds within 10 seconds. Given an audit entry, When filtering by Client, Matter, Event Type, or Date Range, Then results return within 2 seconds for datasets up to 10,000 events and include only matching entries.
No Storage of Raw PAN/Bank Data on CaseSpark Servers
Given any card or bank entry flow, When a QA proxy inspects network requests from the browser, Then PAN and bank routing/account numbers are sent only to the processor domain and never to CaseSpark domains. Given tokenized methods exist, When querying the CaseSpark database and logs, Then only tokens, last4, brand/bank name, and expiry/account type are present; no full PAN, CVV, or full account/routing numbers exist. Given card/ACH details are displayed in the app, When viewing any screen, Then sensitive data is masked and unmasking is not possible for staff or clients. Given logs and error traces, When a processor error occurs, Then logs redact sensitive payloads and do not contain PAN or bank numbers. Given PCI scope review, When generating compliance artifacts, Then the integration pattern qualifies for SAQ A/outsourced model (hosted fields/redirect) and evidence of tokenization is documented.
One‑Tap Funding Links via SMS/Email
"As a billing coordinator, I want to send clients one-tap payment links when balances are low so that we can quickly replenish trust without phone tag."
Description

Generate secure, expiring payment requests with prefilled amounts and pay-by dates when balances fall below thresholds. Deliver one-tap links via SMS and email with branded, localized templates and fallback channels; include deep links to a mobile-optimized, PCI-compliant payment page supporting Apple Pay/Google Pay, ACH, and cards. Track delivery, opens, clicks, and completion; auto-resend reminders with configurable cadence and quiet hours. Support client self-selection of payment method, capture optional memo, and update matter ledger in real time upon authorization or settlement events. Provide staff visibility into request status and a manual resend/cancel function.

Acceptance Criteria
Trigger-Based Payment Request Generation
Given a matter’s trust balance falls below its configured minimum threshold And the client’s consent settings and top-up rules are on file When Auto Replenish evaluates the balance event Then the system creates a payment request with a prefilled amount that brings the balance to the target threshold (or uses the configured fixed top-up amount), rounded to the nearest cent And sets a pay-by date according to the firm default (e.g., N days) or matter-specific override And generates a unique, single-use, tokenized link with a configurable expiry (default 72 hours) And records the request with status "Pending" plus audit metadata (createdBy=system, timestamps, matterId, clientId) And prevents duplicate request generation for the same matter within the configured deduplication window
Secure One‑Tap Link Delivery via SMS and Email
Given a payment request is in Pending status When delivery is initiated Then the system sends branded, localized messages via SMS to the verified mobile and email to the primary address, unless a channel is opted out And each message contains a one‑tap deep link and clearly shows amount and pay‑by date without exposing sensitive payment data And messages are delivered over secure channels (HTTPS link; no HTTP) and render a tappable button in common mobile/email clients And hard bounces or carrier failures are detected and logged within 60 seconds And a fallback attempt is made via the alternate channel within 5 minutes of a failure And delivery events update the request status and analytics
Mobile‑Optimized PCI‑Compliant Payment Page
Given the recipient taps the link before it expires When the payment page loads Then the page is responsive and loads within 2 seconds at p95 on 4G networks And shows firm branding, matter reference, prefilled amount, and pay‑by date And offers Apple Pay (iOS/Safari where available), Google Pay (Android/Chrome), ACH, and card options per firm/region settings And allows the client to select a method, enter required details, and optionally add a memo (max 200 characters) And disables the Pay button until required inputs are valid And tokenizes sensitive fields so no card data touches CaseSpark servers (PCI SAQ A scope) And expired/invalid links route to a safe page with an option to request a new link
End‑to‑End Engagement and Payment Event Tracking
Given a payment request exists When delivery, open, click, authorization, settlement, failure, cancel, or expiry events occur Then each event is captured with timestamp, channel, and requestId and is idempotent across retries/webhooks And request status transitions are enforced (e.g., Pending→Delivered→Opened→Clicked→Authorized→Settled) with guards against invalid transitions And events are visible in the staff console timeline and exposed via API And PII is limited to what is necessary; IPs are masked and retained per policy
Automated Reminders with Configurable Cadence and Quiet Hours
Given a request that is not Settled, Canceled, or Expired And a reminder schedule and quiet hours are configured When a reminder becomes due Then the system schedules the reminder to send outside the client’s local quiet hours And includes the same link if still valid; otherwise generates a new link, invalidates the old one, and updates tracking And stops further reminders after settlement, cancelation, or reaching the configured max attempts And allows staff to pause or resume reminders per request
Real‑Time Ledger Updates and Staff Controls
Given a payment authorization or settlement is received from the gateway When the event is processed Then the matter trust ledger updates in real time: And on Authorization, a pending deposit entry is created and excluded from available balance And on Settlement, the pending is converted to available and the running balance is updated And on Failure/Refund/Chargeback, reversing entries are posted And amounts match gateway amounts to the cent with currency support And staff can view status, delivery outcomes, amount, due date, and event timeline in the console And staff can manually resend (choose channels), cancel (invalidate link), or copy the link, with all actions audited and permission‑gated
Jurisdiction‑Compliant Trust Accounting & Ledger Posting
"As a managing attorney, I want replenishments to post correctly to each matter’s trust ledger under my state’s IOLTA rules so that our firm stays compliant and audit-ready."
Description

Allocate replenishments to the correct client-matter trust ledger with strict IOLTA and state bar compliance, preventing commingling and ensuring separation from operating funds. Create immutable ledger entries with source, authorization reference, method, settlement status, and responsible user. Handle ACH holds and reversals, NSF events, chargebacks, and partial settlements with automatic adjustments and notifications. Provide reconciliation exports (CSV/OFX) and integrations to common accounting systems, plus audit-ready reports showing balances, replenishments, and events by matter, client, and jurisdiction. Enforce rules that block disbursements until funds are cleared based on method-specific settlement timelines.

Acceptance Criteria
Immutable Ledger Entry for Auto-Replenish Deposit
Given a client matter with a configured jurisdictional trust account and prior written consent on file with authorizationRef "AR-123" When a $1,000 auto-replenish is initiated via credit card and accepted by the processor Then the system posts an immutable trust ledger credit with fields present and non-null: clientId, matterId, jurisdiction, trustAccountId, source="Auto Replenish", authorizationRef="AR-123", paymentMethod="Card", grossAmount=1000.00, feesAmount posted to operating (not deducted from trust), netAmount=1000.00, settlementStatus in {"Pending","Cleared"}, settlementEta timestamp, processorTxnId, responsibleActor="System", createdAt (UTC), currency And the original entry cannot be edited; any correction occurs via separate reversing/adjusting entries that reference the original entryId and append to the audit log
Method-Specific Settlement Timeline Enforcement for Disbursements
Given an ACH deposit with policy hold of 5 business days or until processor webhook status="Cleared" When a user attempts any disbursement from uncleared ACH funds before clearance Then the disbursement is blocked with reason="SettlementHold" and message indicating the expected release date/time And availableForDisbursement excludes all uncleared ACH amounts Given a card deposit with settlementStatus="Cleared" When a user disburses an amount <= availableForDisbursement Then the disbursement succeeds and the trust ledger records a debit linked to the original deposit; no block reason is shown
ACH Holds, NSF, Reversals, and Chargebacks Handling
Given an ACH deposit posted as settlementStatus="Pending" When the bank returns NSF with reason code (e.g., R01) Then the system posts an automatic reversing debit to the same client-matter trust ledger equal to the pending net amount, sets settlementStatus="Failed", links reversal to the original entry via relatedEntryId, and availableForDisbursement remains unchanged (never negative) And notifications are sent to the responsible attorney and client with the reason code and one-tap top-up link; Auto Replenish is triggered if thresholds are breached Given a card deposit later receives a chargeback When a chargeback event is received from the processor Then the system posts a reversing debit, marks settlementStatus="Reversed", captures processor reason codes, freezes further disbursements from the affected deposit amount, and logs the processor event id in the audit trail
No Commingling and Correct Jurisdictional Ledger Allocation
Given a replenishment for Client A, Matter M, Jurisdiction=CA When the payment settles Then funds are credited only to Matter M's CA IOLTA trust ledger; no portion is posted to operating or any other client/matter ledger And processor fees are recorded to operating (expense/liability) and are not deducted from the trust ledger And attempts to allocate replenishment across multiple matters or jurisdictions are rejected with error code="LedgerAllocationMismatch" And transfers between operating and trust are blocked unless via approved withdrawal/disbursement workflows; interest is not recorded as firm revenue
Reconciliation Exports (CSV/OFX) and Accounting Integrations
Given a date range and jurisdiction filter When the user generates a reconciliation export Then CSV and OFX files are produced containing: date, clientId, matterId, jurisdiction, entryId, entryType (credit/debit/adjustment), amount, runningBalance, settlementStatus, processorTxnId, authorizationRef, responsibleActor, memo And per-matter subtotals and grand totals in the export match on-screen balances within ±$0.00 And the OFX validates against schema and imports without error into supported accounting systems Given an integration to QuickBooks Online or Xero is connected When the user pushes the reconciliation for the period Then deposits post as Debit=Trust Bank, Credit=Trust Liability; disbursements post as Credit=Trust Bank, Debit=Trust Liability, with matter-level tracking; pushes are idempotent by processorTxnId and do not duplicate on retry
Audit-Ready Reporting by Matter, Client, and Jurisdiction
Given a selected matter/client/jurisdiction and date range When the user generates an audit report Then the report includes opening balance, each replenishment/disbursement/adjustment with timestamps, responsible actor, method, authorizationRef, settlement timeline (pending/cleared/failed/reversed), and closing balance And each line item links to an immutable ledger entryId and related processorTxnId And an exportable audit log shows all notifications, holds, reversals, and user actions for the period And the report is read-only and tamper-evident; any later adjustments appear as new entries in subsequent reports
Partial Settlement Handling and Available Balance Calculation
Given an authorization of $1,000 results in partial settlement of $700 and $300 pending or reversed When settlement events are received from the processor Then the ledger reflects a cleared credit of $700 and a separate pending or reversal entry for $300 linked to the original authorization And availableForDisbursement equals $700; attempts to disburse above $700 are blocked with reason="InsufficientClearedFunds" And notifications inform staff and client of the partial settlement; Auto Replenish evaluates thresholds and issues a top-up request if needed
Workflow Funding Gates & Auto‑Resume
"As an attorney, I want CaseSpark to pause non-critical tasks when a trust balance is insufficient and automatically resume after funding so that filings aren’t submitted without coverage and my team doesn’t babysit the process."
Description

Introduce funding gates that pause non-critical workflow steps (e.g., document assembly, court filing submission) when a matter’s trust balance is below its configured threshold. Surface clear banners and task blocking reasons to staff, notify assigned users, and optionally show clients a status message in the portal. Allow authorized overrides with reason capture and configurable risk policies. Automatically detect when funding is confirmed (authorization or settlement, per rule) and resume blocked steps in sequence, updating due dates and SLA timers. Expose gate events via API/webhooks for coordination with external systems.

Acceptance Criteria
Gate Activation on Low Trust Balance and Staff Visibility
Given a matter with a trust balance threshold of $1,500 and an available trust balance of $1,200 at a non‑critical step named "Court Filing Submission" When the workflow engine evaluates pre‑step funding rules Then the step is paused and marked "Blocked by Funding Gate" And a red banner is displayed on the matter and task detail with text containing the current balance ($1,200) and threshold ($1,500) And the blocking reason is shown in the task list row tooltip and task detail view And steps labeled as critical are not paused And an audit event "gate.opened" is recorded with timestamp, matter ID, step ID, threshold, available balance, and deficit
Assigned User Notifications on Gate Open
Given a matter has an assigned attorney and intake staff When a funding gate opens Then an in‑app notification is created for each assigned user containing the matter name/ID, blocking step, current balance, threshold, and a deep link to the task And an email notification is sent to each assigned user within 60 seconds of gate open And identical gate‑open notifications for the same matter/step are suppressed for 15 minutes to avoid duplicates And if the gate remains open for more than 24 hours, a reminder notification is sent and the matter is added to the "Funding Needed" queue
Client Portal Status Message (Optional)
Given client portal visibility for funding status is enabled on a matter When a funding gate is open Then the client portal shows a status message "Action needed: Add funds to proceed" and the last updated timestamp And no confidential internal ledger details are shown; only the required additional amount is shown if the "show amount" toggle is enabled And when portal visibility is disabled for the matter, no funding status message is visible to the client And an analytics event "client_gate_viewed" is emitted once per client session when the banner is displayed
Authorized Override With Reason Capture and Risk Policy Enforcement
Given a user with the "Funding Gate Override" permission attempts to proceed a blocked step When they click "Override" and provide a reason of at least 10 characters and select an override scope (one‑time for this step, for N hours across this matter, or for this workflow) Then the system records an override with reason, scope, expiration (if any), user ID, timestamp, and affected step(s) And the blocked step proceeds immediately while the gate remains logically open until cleared or expiration And users without the permission cannot see or invoke the override control And if the deficit exceeds the configured risk limit for overrides, the override is rejected with the error "Override blocked by risk policy" And all overrides are captured in the audit log and emitted via a "gate.override" webhook
Auto‑Resume on Funding Confirmation and SLA/Due Date Recalculation
Given a matter with resume policy set to "on authorization" or "on settlement" and steps S1→S2→S3 blocked by a funding gate When a matching funding confirmation event (authorization or settlement per policy) is received and reconciled to the matter Then the funding gate closes automatically And the blocked steps resume in their original sequence order, respecting dependencies and prerequisites And each resumed task’s due date is recalculated by adding the exact paused duration to the original due date And SLA timers paused at gate open are resumed from remaining time and reflected in SLA reports And resume processing is idempotent; duplicate confirmation events do not duplicate work or notifications And audit events "gate.closed" and "steps.resumed" are recorded with correlation IDs
Gate Events API and Webhooks
Given a webhook subscription with HMAC signing is configured for the firm When gate events occur (gate.opened, steps.paused, gate.override, gate.closed, steps.resumed) Then a POST is delivered within 30 seconds containing event type, matter ID, step ID(s), threshold, available balance, deficit, user (if any), correlation ID, sequence number, and ISO‑8601 UTC timestamps And events are delivered in causal order per matter using a monotonically increasing sequence number And failed deliveries are retried with exponential backoff for at least 24 hours with a minimum of 10 attempts And each request includes X‑Signature and X‑CaseSpark‑Event‑ID headers for verification and idempotency And a REST API endpoint allows querying the event log filtered by matter ID, date range, and event type
Configurable Thresholds and Evaluation Rules
Given practice‑level default thresholds per workflow step and matter‑level overrides are available When a new matter is created and a workflow is started Then thresholds are initialized from the practice profile and practice area template And authorized users can set per‑matter thresholds in USD with two‑decimal precision and a minimum of $0.00 And the gate evaluates against available trust balance (cleared funds minus pending holds) at each step boundary and every 15 minutes while a step is queued And changes to thresholds take effect immediately, re‑evaluating any blocked/unblocked state, and are written to the audit log And a dry‑run view shows whether current balance would block each upcoming non‑critical step
Payment Failures, Retries & Escalation
"As a firm admin, I want failed auto-charges to trigger smart retries and clear escalation paths so that matters don’t stall and staff know exactly what to do."
Description

Implement intelligent retry logic with configurable backoff, switching to alternate on-file methods when allowed and respecting consent caps. Classify failures (insufficient funds, Do Not Honor, processor outage) and take tailored actions: notify client via multi-channel, generate update-payment links, and create staff follow-up tasks. Provide a dunning sequence with adjustable cadence and escalation to phone/collections after thresholds. Support partial payments toward target amounts and deferrals with new deadlines. Log all events with reason codes and expose metrics (success rate per method, time-to-fund) for continuous optimization.

Acceptance Criteria
Retry with Backoff and Alternate Method Switching for Trust Top‑Up
Given a trust balance falls below the configured threshold and an auto top-up is initiated And the primary payment method fails with a transient error (e.g., processor_outage, network_timeout) When retries are scheduled Then the system schedules up to {config.max_retries} retries using exponential backoff starting at {config.initial_delay_minutes} minutes and capped at {config.max_backoff_minutes} minutes And no retry is scheduled outside {config.retry_window_hours} local hours for the client And after {config.alt_switch_after_retries} failed attempts, the system switches to the next consented on-file payment method if available And the number of auto-charge attempts does not exceed {config.daily_cap} per day and {config.monthly_cap} per month And all retries stop immediately upon a successful charge or consent revocation
Failure Classification and Tailored Actions
Given an auto top-up attempt fails When a processor response code is returned Then the system maps the code to a normalized reason: insufficient_funds, do_not_honor, card_expired, processor_outage, invalid_account, limit_exceeded, unknown And for insufficient_funds: send SMS and email to the client with the outstanding amount and a one-tap secure update-payment link; schedule a retry per {config.retry_policy} And for do_not_honor: send SMS and email; limit retries to {config.dnh_retry_count}; create a staff follow-up task with SLA of {config.staff_sla_hours} hours And for processor_outage: queue retries without notifying the client until outage duration exceeds {config.outage_notify_minutes} minutes; notify staff on first detection And for card_expired: stop auto retries, send update-payment link, and create a task to request new card details And every notification includes a single-use link that expires in {config.link_ttl_hours} hours and associates to the correct matter
Dunning Sequence and Escalation
Given the target top-up amount remains unfunded after initial failure When the dunning workflow is activated Then messages are sent via SMS and email per the configured cadence template (e.g., Day 0, Day 2, Day 5) And each message displays current outstanding amount, next attempt date/time, and a secure one-tap payment/update link And upon reaching {config.max_dunning_attempts} without payment or approved deferral, create a High-priority phone call task for staff And if still unfunded after {config.escalation_days} days, generate a collections referral record (if enabled) and halt auto-attempts And the dunning sequence auto-terminates on successful payment, deferral approval, or consent revocation
Partial Payments and Remaining Balance Handling
Given a top-up target amount of X is due When a partial payment of Y (< X) is received Then apply Y to the trust account immediately and reduce the outstanding to X−Y And update all subsequent notifications and dashboard displays to show the remaining balance and revised next attempt And continue retries/dunning for the remaining balance per {config.retry_policy} And if {config.partial_resume_threshold_percent} is met or exceeded by cumulative payments, resume paused non-critical steps And all currency calculations respect {config.currency_precision}
Deferral Approval with New Deadline
Given staff grants a payment deferral until date D with reason R and terms T When the deferral is recorded Then auto-attempts and dunning pause until D And the client receives SMS and email summarizing the deferral (deadline D, reason R, terms T) And on date D at {config.deferral_charge_time_local}, the system resumes attempts per the active retry policy And any deferral extension or revocation is logged and triggers updated notifications
Event Logging and Metrics Visibility
Given payment failure handling is enabled for Auto Replenish When any attempt, classification, notification, task creation, payment (full/partial), deferral, or escalation occurs Then create an immutable log entry with timestamp, actor, attempt number, method_id, amount, outcome, processor_code, normalized_reason, channels_notified, link_id, task_id (if any) And expose dashboard/API metrics: success_rate_by_method, avg_retries_to_success, median_time_to_fund, failure_reason_distribution, dunning_conversion_rate And logs and metrics are filterable by date range, firm, attorney, matter, and payment method, and exportable to CSV
Consent Caps and Authorization Enforcement
Given per-transaction and monthly consent caps (C_tx, C_mo) and on-file methods with recorded consent When attempting an auto-charge or switching to an alternate method Then verify consent exists for the method and amount <= C_tx and (month_to_date_auto_charges + amount) <= C_mo And if any check fails, block the attempt, log reason consent_cap_exceeded, send an authorization-request link to the client, and create a staff task And for successful charges, store the consent artifact ID with the transaction record

Three‑Way Sync

Posts deposits, trust activity, and trust‑to‑operating transfers to systems like Clio and QuickBooks with precise matter mapping. Generates reconciliation reports and exportable audit packs, shrinking close‑time and eliminating double entry for small teams.

Requirements

Clio and QuickBooks OAuth Connectors
"As a firm administrator, I want to securely connect our Clio and QuickBooks accounts so that CaseSpark can post trust transactions without manual exports or credential sharing."
Description

Implement secure OAuth 2.0 integrations for Clio and QuickBooks, including token acquisition and automatic refresh, granular scopes for trust and payments access, and per-tenant environment selection (sandbox/production). Provide connect/disconnect flows, encrypted credential storage, health checks, and permission validation. Support firm-level service connections and user-level consent where required, ensure multi-tenant isolation, and expose a connection status API for the sync layer.

Acceptance Criteria
Clio OAuth Connect with Granular Scopes and Environment Selection
Given a tenant admin selects Clio environment (Sandbox or Production) When they click Connect and complete OAuth consent Then the system requests only the predefined scopes required for trust activity, payments, and matter mapping and records the granted scopes And exchanges the authorization code for access and refresh tokens and encrypts and stores them scoped to the tenant and environment And validates connectivity by calling Clio identity and a minimal permissions endpoint, receiving HTTP 200 And displays connection state = Connected with environment label within 5 seconds of callback And if consent is denied or scopes are insufficient, state = ActionRequired with a remediation message
QuickBooks OAuth Connect with Realm and Environment Selection
Given a tenant admin selects QuickBooks environment (Sandbox or Production) When they click Connect, select a company (realm), and approve consent Then the system requests only the predefined scopes required for deposits, trust activity, and transfers And exchanges the authorization code for tokens, stores them encrypted with tenant, environment, and realmId And verifies connectivity by retrieving company info and Chart of Accounts and reading the Deposits endpoint, receiving HTTP 200 And displays connection state = Connected with company name and environment within 10 seconds of callback And if the user cancels or no company is selected, state = ActionRequired with guidance to re-connect
Automatic Token Refresh and Expiry Handling
Given an access token will expire within 5 minutes or an API call returns HTTP 401/403 due to token expiration When the sync layer issues the next API request Then the system obtains a new access token using the stored refresh token without user interaction and retries the original request once And rotates and replaces the stored tokens atomically and updates lastRefreshedAt And enforces exponential backoff and marks the connection Unhealthy after 3 consecutive refresh failures, emitting an alert event
Encrypted Credential Storage and Multi‑Tenant Isolation
Given tokens and integration metadata are stored Then all secrets are stored encrypted at rest using the platform KMS; plaintext is never exposed via UI or APIs And secrets are scoped by tenant and environment; cross-tenant access attempts are denied with HTTP 403 and logged And backup/restore of the secrets preserves encryption and scoping And automated isolation tests attempting to access another tenant’s tokens fail 100% of trials
Permission Validation and Connection Health Checks
Given a connection exists When a scheduled health check runs every 15 minutes or an on-demand check is invoked Then the system validates reachability, token validity, and required scope presence by calling identity and a minimal protected resource; non-200 results set state = Unhealthy And insufficient scopes set state = ActionRequired with a machine-readable code INSUFFICIENT_SCOPES And health check results are recorded with timestamp, latency, and lastError for retrieval via the status API
Disconnect Flow with Token Revocation and Data Cleanup
Given a tenant admin clicks Disconnect for Clio or QuickBooks When the action is confirmed Then the system revokes tokens at the provider (if supported), deletes local encrypted tokens and integration metadata, cancels scheduled jobs, and removes webhooks And preserves immutable audit logs and historical sync records And sets connection state = Disconnected within 5 seconds and prevents further API calls And re-connecting establishes a new connection without residual configuration conflicts
Connection Status API for Sync Layer
Given the sync layer queries GET /integrations/status for a tenant When the request is authenticated with a service token Then the API returns 200 with an array of connections containing: system (Clio|QuickBooks), environment, status (Connected|Unhealthy|Disconnected|ActionRequired), grantedScopes, realm/company mapping info, lastSuccessfulCallAt, lastHealthCheckAt, and message And changes in connection state are reflected by the API within 60 seconds of occurrence And unauthorized requests return 401; requests for another tenant return 403; rate limit is 60 req/min with 429 on exceed
Matter & Ledger Mapping Engine
"As a bookkeeper, I want matters and accounts mapped correctly across systems so that deposits and transfers post to the right ledgers without rework."
Description

Create a rules-driven mapping engine that links CaseSpark matters to Clio matters and QuickBooks customers/projects, and maps trust, operating, and clearing accounts to the correct Chart of Accounts. Provide jurisdiction-aware templates, configurable naming/numbering conventions, duplicate detection, validation of required mappings, and support for multiple trust bank accounts per firm. Include bulk import/export of mappings, versioning with change history, and an API/UI for reviewing and adjusting mappings safely.

Acceptance Criteria
Create Matter Mapping from Jurisdiction Template
Given a new CaseSpark matter with jurisdiction and practice area selected and firm integrations to Clio and QuickBooks are connected When the user initiates mapping creation using the relevant jurisdiction template Then the engine proposes a link-or-create Clio Matter and QuickBooks Customer/Project according to template rules And the engine selects trust, operating, and clearing GL accounts mapped per the template and firm Chart of Accounts And required fields (e.g., client, matter ID, jurisdiction, primary attorney, default trust account) are validated with actionable inline errors if missing or invalid And a preview displays the external identifiers and GL accounts to be saved And saving persists an Active mapping with a unique Mapping ID and timestamps And the proposal is generated within 2 seconds for 95% of requests under normal load
Enforce Naming and Numbering Conventions
Given firm-level naming/numbering configuration (e.g., {YY}-{PracticeCode}-{Seq}, min/max length, padding, separators) and external system character constraints When generating or validating matter identifiers for Clio and customer/project names for QuickBooks Then the engine enforces the configured pattern and reserves the next sequence atomically per scope (e.g., per jurisdiction/practice) And rejects disallowed characters and exceeds-length values per Clio/QuickBooks constraints with specific error messages And ensures uniqueness across the configured scope and target systems before save And provides a preview of the final identifier and prevents save if preview and validated value diverge
Detect and Prevent Duplicate Mappings
Given an existing mapping links CaseSpark Matter M1 to Clio Matter C1 and/or QuickBooks Customer/Project Q1 When a user attempts to create or update a mapping that would duplicate any of these keys (CaseSpark Matter ID, Clio Matter ID, QuickBooks Customer/Project ID/Name within firm scope) Then the engine blocks the save and identifies the conflicting Mapping ID(s) and field(s) in the error response And offers a "Link existing" action when the intent is to associate the existing external entity And records the blocked attempt in the change log with user, timestamp, and reason
Support Multiple Trust Bank Accounts per Firm
Given a firm has multiple trust bank accounts configured and mapped to QuickBooks GL accounts and allowed jurisdictions When creating or editing a matter mapping Then the user can select exactly one default trust account for the matter from the allowed list And Three‑Way Sync postings for that matter use the selected trust account consistently And the engine prevents selection of deactivated or unmapped trust accounts and displays a clear error And changing the default trust account is versioned and logged, and takes effect only for subsequent postings
Bulk Import/Export of Mappings with Validation
Given a CSV/XLSX file that conforms to the published schema (including required columns for CaseSpark Matter, Clio Matter, QuickBooks Customer/Project, account mappings, and version note) When the user uploads the file with Dry Run enabled Then the engine validates all rows and returns a downloadable report with row-level Pass/Fail and reasons, and no data is persisted When the user confirms import without Dry Run Then valid rows are created/updated atomically per row; invalid rows are skipped; a summary shows counts of created, updated, skipped, with an error file for remediation And imported mappings observe all duplicate detection, naming, and COA validation rules And exporting mappings produces a file in the same schema including version, author, and timestamps for each mapping
Versioning, Change History, and Rollback
Given an existing mapping version v1 When a user edits fields and saves version v2 with an optional change note Then the system stores v2 with author, timestamp, and a field-level diff from v1 And prior versions remain immutable and retrievable via UI and API And a user with appropriate permission can roll back to any prior version, creating a new version that restores those values And the audit pack export for a date range includes every version event and diff for included mappings
API/UI Safe Edit with Concurrency and Permissions
Given mappings can be modified via UI and REST API When two clients attempt to update the same mapping concurrently Then optimistic concurrency control using a version token/ETag prevents lost updates; the second write returns 409 Conflict with guidance to refresh And server-side validation is identical for API and UI requests And role-based permissions restrict create/update/delete to authorized roles; unauthorized attempts return 403 and are logged And every create/update/delete event logs user/client, timestamp, and before/after values with sensitive fields redacted per policy
Idempotent Trust Transaction Posting
"As a solo attorney, I want trust deposits and transfers posted automatically to both Clio and QuickBooks so that my records stay accurate without double entry."
Description

Build a posting service that records deposits, trust activity (fees, refunds, disbursements), and trust-to-operating transfers in Clio and QuickBooks with strict idempotency to eliminate duplicates. Ensure correct double-entry in QuickBooks using mapped accounts, preserve transaction order and cross-links, and attach references/memos back to CaseSpark matters. Support real-time and batched posting, partial applications, currency/rounding rules, voids/reversals with audit linkage, and fallbacks to draft when mappings or validations fail.

Acceptance Criteria
Idempotent Deposit Posting
Given a CaseSpark trust deposit has a unique transaction_id and idempotency_key When the posting service is invoked multiple times (real-time retry or batch replay) Then exactly one deposit is created in Clio and QuickBooks for that transaction, and subsequent invocations return an idempotent success without creating additional records And the deposit is associated to the correct matter/customer via configured mappings, and memos include the CaseSpark Matter ID and transaction_id And CaseSpark stores the external record IDs once and marks the transaction as posted without duplicates
Correct Double-Entry and Account Mapping in QuickBooks
Given a configured mapping for trust bank, trust liability, operating bank, income/expense, and rounding accounts When posting deposits, fee applications, refunds, disbursements, and trust-to-operating transfers Then QuickBooks entries are balanced (total debits equal total credits) for each transaction And the accounts used match the configured mapping for the specific transaction type And trust bank and trust liability balances move in equal and opposite directions for trust inflows/outflows And for trust-to-operating applied to invoices, AR is reduced by the applied amount, operating bank increases accordingly, and trust liability/bank decrease by the same amount And for refunds/disbursements, the payee/vendor or client is set per mapping
Trust Activity Posting with References
Given trust fees, refunds, and disbursements exist for a matter When the posting service processes these items Then corresponding records are created in Clio and QuickBooks with matching amounts, dates, and descriptions And each external record contains a memo/reference with the CaseSpark Matter ID and transaction_id And CaseSpark persists the external record IDs and associates them to the source transaction And if one external system succeeds and the other fails, the result is recorded as partial with automatic idempotent retries until both systems reflect the transaction or the error is resolved
Transaction Ordering and Cross-System Links
Given a sequence of transactions for the same matter with timestamps and sequence numbers When posting in batch or near-real-time Then transactions appear in Clio and QuickBooks in the same chronological order as the source sequence And each posted record is cross-linked via a shared correlation_id/idempotency_key in memo/reference fields where supported, and stored bi-directional links in CaseSpark (Clio_id and QuickBooks_id) And dependent transactions are deferred until predecessors succeed, with dependency status recorded
Real-Time and Batch Posting Modes
Given real-time mode is enabled When a transaction is finalized in CaseSpark Then the service attempts immediate posting and returns a definitive success/failure with the idempotency_key Given batch mode is enabled When the scheduled job runs Then transactions are posted in stable order with configurable batch size and retry/backoff policy, and successful items are not retried And transient failures are retried idempotently without creating duplicates
Partial Applications with Currency and Rounding Rules
Given an invoice of 1000.00 and a trust balance of 600.00 in the same currency When applying trust funds Then 600.00 is applied to the invoice, invoice balance becomes 400.00, and trust liability/bank decrease by 600.00 in both systems And amounts on Clio and QuickBooks match to the minor unit (e.g., cents) with no discrepancy Given amounts that require rounding to the currency minor unit When posting Then line items are rounded per currency rules, totals match the source within ±0.01 of the currency, and any residual posts to the configured rounding account with a clear memo And if currency configuration is unsupported for the matter, the transaction is placed in Draft with an explicit error code
Voids/Reversals and Draft Fallback Handling
Given a previously posted transaction When a void is requested Then a reversal record is created in both systems that fully offsets the original, the original is not deleted, and both records cross-reference each other and the CaseSpark reversal_id Given a mapping or validation failure (e.g., missing account mapping, closed period, unmapped matter) When attempting to post Then no external records are created, the item is saved as Draft with a machine-readable error code and human-readable message, and the audit log captures the failure context Given the failure is corrected When the same transaction is retried with the original idempotency_key Then exactly one set of external records is created and the Draft transitions to Posted with preserved audit linkage
Reconciliation Reports & Audit Packs
"As a managing partner, I want downloadable reconciliation reports and audit packs so that I can substantiate trust balances quickly during monthly close or audits."
Description

Generate monthly trust reconciliations that tie bank statements to trust ledgers and matter sub-ledgers, flag variances and uncleared items, and provide roll-forward schedules. Produce an exportable audit pack (CSV/PDF/JSON) including transaction registers, matter balance summaries, reconciliation worksheets, exception logs, and mapping snapshots. Support bank statement import, timestamped and hash-verified bundles, and configurable retention for compliance and audits.

Acceptance Criteria
Monthly Bank Statement Import and Validation
Given a trust bank statement file for a single month (CSV, OFX/QFX, or PDF) for a configured trust account When the user uploads the file Then the system verifies the account identifier matches the configured trust account, the statement covers exactly one contiguous calendar month, and opening and ending balances exist in the file And the system imports 100% of statement transactions with posted date, description, amount, and reference number captured, assigning a unique source-id per row And duplicate re-uploads of an identical statement are detected and handled idempotently (no duplicate transactions created) And if parsing fails, the user receives a specific error with the first failing row and field; no partial import is committed
Trust Reconciliation Balances Tie-Out
Given the imported bank statement for month M and the internal trust ledger and matter sub-ledgers for month M When the reconciliation is executed Then the book ending balance equals the bank statement ending balance with variance = $0.00 And every bank transaction is either matched to a ledger entry or listed in the Unmatched section with a reason code (MissingLedger, MissingBank, AmountMismatch, DateOutsidePeriod) And the sum of all matter sub-ledger ending balances equals the trust ledger ending balance with variance = $0.00 And the reconciliation worksheet displays opening balance, deposits, withdrawals, uncleared items, adjustments (if any), ending balance, and calculated variance
Uncleared and Exception Items Detection
Given checks and deposits recorded in the trust ledger that have not cleared by month-end When uncleared items are computed during reconciliation Then uncleared items are listed and grouped into age buckets (0–30, 31–60, 61–90, >90 days) with counts and totals per bucket And items older than 60 days are flagged High severity; items older than 30 days are flagged Medium severity And exceptions include negative matter balances, orphaned transactions lacking matter mapping, and duplicate reference numbers, each entry showing matter, date, amount, and reason code
Roll-Forward Schedule Generation
Given a closed prior month and current month transactions When generating the roll-forward schedule Then Opening = Prior Month Ending for the trust ledger and for each matter sub-ledger And Ending = Opening + Net Activity with variance = $0.00; any non-zero variance blocks period close And the schedule shows per-matter beginning balance, receipts, disbursements, transfers, and ending balance, with column totals reconciling to the trust ledger
Audit Pack Assembly and Export
Given a reconciliation for month M is marked Closed When the user requests an audit pack export Then the system produces a bundle containing: transaction registers (bank and ledger), matter balance summary, reconciliation worksheet, exception log, and mapping snapshot And the bundle is available in CSV, PDF, and JSON formats; each filename includes firm identifier, trust account, and YYYY-MM And the JSON output validates against the published schema (all required fields present); schema validation errors prevent export with a descriptive error And the export completes within 30 seconds for data sets up to 5,000 transactions and 2,000 matters
Timestamped and Hash-Verified Bundle
Given an audit pack bundle is generated When the bundle is finalized Then a manifest.json is created with SHA-256 hashes for each file, UTC timestamp, generator version, and user id And the bundle receives an overall SHA-256 hash; both manifest and overall hash are stored immutably And upon any later download or verification, recomputed hashes must match stored hashes; any mismatch raises a tamper alert and blocks reopening or alteration of the closed period
Configurable Retention and Legal Hold
Given a configurable retention policy (e.g., 7 years) for audit packs When the nightly retention job runs Then bundles older than the retention period without legal holds are queued for purge and require admin approval And purge removes bundle files and data while retaining a tamper-evident purge record (bundle id, hash, purge date, approver) And bundles under legal hold are excluded from purge until the hold is released And all access, export, hold placement/removal, and purge actions are audit-logged with user id, timestamp, IP, and outcome
Sync Orchestration & Error Recovery
"As a system operator, I want resilient sync with retries and replay so that transient outages don’t cause data loss or mismatched ledgers."
Description

Provide a scheduler and webhook-driven pipeline for incremental sync, initial backfill, and near real-time updates. Implement at-least-once delivery with idempotency keys, exponential retries, dead-letter queues, replay tooling, and rate limiting per tenant and connector. Expose operational metrics and structured logs, surface actionable error messages, and allow maintenance windows and safe shutdown to protect data consistency.

Acceptance Criteria
Initial Backfill via Scheduler
Given a tenant enables initial backfill for a connector with a defined time window When the scheduler starts the backfill job Then items are enqueued in deterministic batches by matter and ascending modified time And each batch respects configured per-tenant and per-connector rate limits And progress checkpoints are persisted at least every 1,000 records or 60 seconds, whichever comes first And if the job is interrupted and restarted, processing resumes from the last successful checkpoint with no duplicate downstream writes And 100% of eligible records within the requested window are processed and acknowledged And progress (percent complete, processed count, ETA) is exposed via metrics and an API endpoint
Webhook-Driven Near Real-Time Updates
Given a valid webhook event containing a unique idempotency key and event timestamp for tenant T When the event is received by the ingestion endpoint Then the endpoint responds with 2xx within 2 seconds And the event is enqueued once and processed within 60 seconds at the 95th percentile under nominal load And duplicate deliveries with the same idempotency key do not produce duplicate downstream writes And out-of-order events for the same source record are resolved deterministically by event timestamp with documented conflict rules And if a downstream rate limit is encountered, the event is retried with backoff and no data is lost
Idempotency and At-Least-Once Delivery
Given any write operation to a downstream system initiated by sync When the same operation is attempted multiple times due to retries or duplicate notifications Then the operation is applied at least once and no more than once to the downstream system And idempotency is enforced using a key composed of tenantId + connector + sourceRecordId + operationType with a minimum deduplication window of 24 hours And idempotency decisions (hit/miss) are recorded in structured logs and metrics
Exponential Retry, Dead-Letter Queue, and Replay
Given a transient processing error such as 5xx, timeout, or 429 When the worker retries the operation Then exponential backoff with full jitter is applied with initial delay >= 1s and max backoff <= 5m And after a maximum of 7 attempts the message is moved to a dead-letter queue with error context and correlationId preserved And operators can replay DLQ items filtered by tenant, connector, time range, and error code, in dry-run or live modes And replay preserves original idempotency keys and ordering guarantees within the same source record And successful replays update metrics and remove items from the DLQ
Per-Tenant and Per-Connector Rate Limiting
Given multiple tenants and connectors are active concurrently When the pipeline processes work Then separate rate limits are enforced per tenant and per connector using token buckets (or equivalent) And no single tenant can exceed its configured share or starve others; other tenants continue processing And 429 responses from downstream systems trigger adaptive backoff without job failure And rate-limit counters, current quotas, and throttled request counts are exposed via metrics and an admin API
Operational Metrics, Structured Logs, and Actionable Errors
Given the sync pipeline is running When observing system behavior and failures Then metrics are emitted for throughput (records/s), lag (time since source change), success/failure counts, retry counts, DLQ size, and p95/p99 processing latency per connector and tenant And logs are structured (JSON) and include timestamp, level, tenantId, connector, matterId (when applicable), correlationId, idempotencyKey, and errorCode And user-facing errors map to internal error codes and include remediation steps and a link to documentation or replay action And dashboards visualize key metrics and alert when lag > 5 minutes for > 10 minutes or DLQ size exceeds configured thresholds
Maintenance Windows and Safe Shutdown
Given a scheduled maintenance window for tenant T or the cluster When the window begins or a graceful shutdown is triggered Then the scheduler stops starting new jobs and workers drain in-flight tasks up to a configurable timeout And no partial writes are committed; interrupted work resumes safely via idempotency on restart And webhook ingestion is paused with 2xx acknowledgment and events are queued for later processing And after the window, processing resumes automatically from the last checkpoint with data consistency preserved
Trust Compliance Guardrails
"As a compliance officer, I want guardrails that block non-compliant trust postings so that our firm avoids ethical violations and penalties."
Description

Enforce IOLTA/trust accounting rules by preventing negative matter balances, commingling, or transfers without sufficient funds. Require complete mappings before posting, validate transaction metadata (matter, payee, dates), and apply jurisdiction-aware constraints. Maintain an immutable audit trail with who/what/when, including before/after values, and block postings that would violate compliance with clear remediation guidance.

Acceptance Criteria
Block Trust Disbursement Causing Negative Matter Balance
Given matter M-123 has an available trust balance of $500 And there are no pending deposits or holds When a user attempts to post a trust disbursement of $600 for M-123 Then the system blocks the posting And displays an error: "Insufficient trust funds; maximum allowable disbursement is $500.00" And no transaction is created locally or synced to Clio or QuickBooks And an audit record is written with status "Blocked", including user id, timestamp, matter id, attempted amount, and computed available balance
Prevent Commingling Across Trust and Operating Accounts
Given a user selects source account = Trust (IOLTA) and destination ledger = Firm Revenue Or selects source account = Operating and labels the transaction as "Trust Deposit" When the user attempts to post the transaction Then the system blocks the posting for commingling risk And the error specifies: "Trust funds cannot be posted to revenue or operating accounts directly; use Trust-to-Operating Transfer tied to a matter" And no entries are created in either system And an audit record is created with violation code COM-001
Enforce Sufficient Funds on Trust-to-Operating Transfer
Given matter M-456 has available trust funds of $1,200 after accounting for holds and pending disbursements When a user initiates a trust-to-operating transfer of $1,000 for earned fees Then the transfer is permitted And the system creates a trust debit of $1,000 for M-456 and an operating receipt mapped to the correct income ledger and client/matter in Clio and QuickBooks And the remaining available trust balance becomes $200 And an audit record captures before/after balances, user id, and linked external IDs
Require Complete Mappings Before Posting
Given the matter M-789 lacks mapping to a Clio matter ID or QuickBooks customer/job Or the trust bank account lacks a mapped GL account When a user attempts to post any trust transaction for M-789 Then the system blocks the posting And the error lists all missing mappings with direct links to configure each And no partial data is posted to any external system And the audit record includes the list of missing mappings
Validate Transaction Metadata and Jurisdiction Constraints
Given the matter jurisdiction is California And the user enters a trust disbursement dated in a closed accounting period and payable to "Cash" When the user submits the transaction Then the system blocks the posting And the error cites violations JUR-CA-TRUST-001 (no cash withdrawals) and PER-001 (date in closed period) with remediation steps And field-level validation highlights the invalid fields And no data sync occurs
Immutable Audit Trail With Before/After Values
Given a trust transaction T-100 was posted successfully When a user attempts to edit amount, date, matter, payee, or memo of T-100 Then direct edit is disallowed And the system requires a reversal entry and a new corrected entry And the audit trail stores who initiated the reversal, timestamps, original values, new values, and links all related entries And the audit pack export includes the full chain with cryptographic hash and cannot be deleted by any role
Remediation Guidance for Blocked Compliance Violations
Given a posting is blocked due to insufficient funds or missing mappings When the error is shown Then the message includes: the computed allowable amount (if funds-related), a checklist of missing mappings with links, and a link to jurisdiction-specific guidance And the user can click "Fix Now" to navigate to the exact configuration or reduce the amount to the allowable value And upon remediation, re-validation passes and allows posting without re-entering previously valid fields
Admin Console & Review Workflow
"As an office manager, I want a simple console to review and approve sync items so that we can close the books quickly with confidence."
Description

Deliver a role-based UI for connection management, mapping configuration, sync monitoring, and a review queue for pending/failed postings. Enable bulk approvals, safe corrections with full audit history, retries/resends, and export of logs. Provide filters, search, and notifications (email/Slack) for exceptions and end-of-day summaries, ensuring small teams can manage close with minimal clicks.

Acceptance Criteria
Role-Based Access Control in Admin Console
Given a user with Admin role, when they log in, then they can access Connection Management, Mapping Configuration, Sync Monitoring, Review Queue, and Exports. Given a user with Reviewer role, when they log in, then they can access Sync Monitoring and Review Queue and cannot access Connection Management, Mapping Configuration, or Exports. Given a user with Read-Only role, when they log in, then they can view Sync Monitoring and Review Queue but cannot approve, retry, edit, export, or change settings. Given a user attempts an unauthorized action, when they perform it, then the control is disabled in the UI and the API returns 403 with an audit entry for the denied attempt including user, action, timestamp, and resource. Given an admin updates a user's role, when the user re-authenticates or refreshes session, then new permissions take effect immediately without requiring deployment or service restart.
Manage Connections for Clio and QuickBooks
Given an Admin adds a Clio or QuickBooks connection, when OAuth completes successfully, then the status displays Connected with last authenticated timestamp and granted scopes. Given a connected integration, when credentials expire or are revoked, then the status changes to Expired or Revoked and new sync attempts are halted with a surfaced exception count and alert. Given an Admin clicks Test Connection, when the system validates reachability and scopes, then it returns Pass or Fail with error details within 10 seconds. Given an Admin disables a connection, when they confirm disable, then future postings to that destination are blocked and new items enter status Blocked - Connection Disabled with no external API calls made. Given multiple connections and environments, when the Admin designates default routing (e.g., Production vs Sandbox), then new postings honor that routing and the selected destination is shown on each item.
Configure and Publish Matter Mapping Templates
Given an Admin opens Mapping Configuration, when they create or edit a template for a destination, then required fields (matter ID, trust account, operating account, GL codes) must be mapped or the Save action is disabled with inline errors. Given changes are saved as Draft, when the Admin clicks Publish and enters release notes, then a new version number is created, an audit log is recorded (who, when, what changed), and the new mapping applies only to postings created after publish time. Given a prior version exists, when the Admin selects Restore on that version, then it becomes the current version and a rollback entry is added to the audit log. Given the Admin runs Mapping Preview with a sample matter, when executed, then the system shows target field values and flags any unmapped or incompatible fields with actionable guidance. Given tax and currency fields are configured, when the template is validated, then the system enforces valid currency codes and tax-rate references required by the destination before allowing publish.
Monitor Sync and Export Logs/Audit Pack
Given a Reviewer or Admin opens Sync Monitoring, when a date range is selected, then the dashboard shows counts by status (Posted, Pending, Failed, In Review) and destination. Given filters (date range, status, destination, account type, matter, amount range) are applied, when the user applies them, then results refresh within 2 seconds for up to 5,000 records. Given a user searches by matter name/ID, transaction ID, or external reference, when the query is submitted, then matching rows are returned with the search terms highlighted. Given an Admin requests Export, when a date range and filters are selected, then a CSV and JSON file containing the filtered records (including correlation IDs, timestamps, users, mapping version, external IDs, and statuses) is generated and available for download within 60 seconds for up to 50,000 records. Given an Admin requests an Audit Pack, when generated, then a ZIP bundle is produced containing the export files, related audit log entries for included items, and a checksum manifest, and the export event itself is recorded in the audit log.
Review Queue for Pending/Failed Postings with Bulk Approvals
Given a Reviewer opens the Review Queue, when items exist in Pending Review or Failed, then each row displays source system, destination, matter, amount, account (trust/operating), mapping version, error code/message, and last attempt time. Given the Reviewer selects multiple eligible items, when Approve is clicked, then a confirmation shows totals and all selected items post with no more than 2 clicks after selection, updating each item status to Posted or Failed with per-item results. Given the Reviewer filters by status, destination, error code, matter, or amount, when filters are applied, then only matching items are displayed and the filter chips are visible for removal. Given an item is missing required mapping or data, when a bulk approval is attempted, then the item is excluded with a clear reason and a one-click deep link to open the correction or mapping page. Given a Reviewer opens an item detail, when viewed, then complete attempt history, audit entries, and raw request/response payloads are visible with PII fields masked by default and a Reveal toggle for users with Admin role.
Safe Corrections with Audit History and Idempotent Retry/Resend
Given a Reviewer edits an item, when they modify allowed fields (e.g., matter mapping, memo, target account), then client and server validations enforce required formats and prevent invalid submissions with inline error messages. Given a correction is saved, when Retry is triggered, then an immutable audit entry records before/after values, user, timestamp, and reason, and the retry uses an idempotency key to prevent duplicate postings downstream. Given a transient error occurs (e.g., 429/5xx), when Retry is clicked or auto-retry policy runs (up to 3 attempts with exponential backoff), then no duplicate entries are created in the destination and each attempt outcome is logged. Given a prior posting was successful but must be resent, when the Reviewer selects Resend and confirms with a reason, then a new posting is created with a linkage to the original and marked as Resend in audit and exports. Given a correction introduces a breaking change, when validation fails, then the system blocks retry and provides actionable guidance or a link to Mapping Configuration.
Exception Notifications and End-of-Day Summaries
Given exception notifications are configured, when a posting fails, then an email and/or Slack message is sent within 10 minutes including matter, amount, destination, error summary, and a deep link to the item. Given Do Not Disturb windows are set, when failures occur during that window, then notifications are deferred unless Override DND for critical errors is enabled, in which case critical failures are delivered immediately. Given End-of-Day summary time and timezone are configured, when that time occurs, then a summary is sent to configured channels with counts by status, oldest unreviewed item age, and top error codes for the day. Given a user or channel opts out, when summaries are sent, then opted-out recipients do not receive messages while team channels do. Given Send Test Notification is clicked, when executed, then the configured channel receives a test message within 1 minute confirming connectivity and configuration.

Compliant Refunds

One‑click, IOLTA‑safe refunds at case close. Calculates residual retainers and outstanding costs, issues refunds to the original payment method, and produces a closing statement and receipt while updating ledgers—delivering a polished client experience with zero compliance anxiety.

Requirements

Residual Retainer Auto-Calculation
"As a firm owner, I want the system to automatically compute the exact refundable retainer after all fees and costs so that I can close matters confidently without manual spreadsheets or compliance risk."
Description

Implements an automated calculator that determines refundable retainer balances at matter close by consolidating trust (IOLTA) balances, outstanding invoices, time entries, expenses, and pending transactions. Applies cut-off dates, uncleared deposit holds, write-offs, and tax handling to ensure accurate net refund amounts. Supports multi-payer and multi-transaction scenarios, split matters under a single client, and itemized allocations (fees, costs, taxes). Integrates with CaseSpark’s time/billing, expense, and trust ledger modules to provide a single, authoritative refund figure ready for one-click disbursement.

Acceptance Criteria
Cut-Off Date and Uncleared Transactions Exclusion
Given a matter has transactions across trust, billing, and expenses And a user selects a cut-off date/time And some deposits are uncleared or pending as of the cut-off And some disbursements are scheduled but not posted as of the cut-off When the calculator runs Then it includes only transactions with posted date/time <= cut-off in the computation And it excludes uncleared deposits and unposted disbursements from trust available And it evaluates dates/times in the firm’s configured time zone And it displays the cut-off used and a count of excluded pending items
Consolidated Trust Balance and Liability Computation
Given trust available as of cut-off is TA And outstanding invoice balance as of cut-off is O And approved, uninvoiced time entries dated <= cut-off total T And approved, uninvoiced expenses dated <= cut-off total E And amounts marked written-off as of cut-off total W When the calculator runs Then liabilities L = (O + T + E) - W (not less than 0) And net refundable R = max(0, TA - L) And if TA < L, it sets R = 0 and surfaces shortfall S = L - TA And it outputs TA, L, R, and S as numeric fields with 2-decimal precision
Write-Offs and Adjustments Application
Given certain invoices, time entries, or expenses are marked written-off with dates <= cut-off And trust adjustments/transfers exist with posted date <= cut-off And a firm tax/write-off configuration is set When the calculator runs Then written-off portions are excluded from liabilities And trust adjustments/transfers are applied to TA before computing liabilities And tax on written-off amounts is treated per configuration (refund_tax_on_writeoff = true|false) And the output lists each applied write-off/adjustment with source IDs and amounts
Tax Handling on Fees and Costs
Given fee and cost items have taxability and tax rate associated to jurisdiction and item date And the firm has a configured tax rounding strategy When the calculator runs Then taxes on outstanding fees/costs are computed using the rate effective on each item’s date as of cut-off And refundable tax is included or excluded per configuration (refundable_tax_policy = include|exclude|limited) And line-level tax is rounded to 2 decimals using half-up, and totals are the sum of rounded lines And the output itemizes tax by rate and category with amounts and rates used
Multi-Payer and Original Payment Method Allocation
Given the trust retainer was funded by multiple payers and transactions And each deposit has payer identity and payment method recorded When the calculator computes net refund R Then it allocates R pro-rata by each payer’s remaining net contribution as of cut-off And it rounds per-payer refunds to 2 decimals and adjusts the largest share to resolve rounding differences (<= $0.01) And it maps each payer’s refund to their original payment methods and transaction IDs in FIFO order within that payer And it outputs a per-payer, per-method allocation table totaling exactly R
Split Matters Under a Single Client
Given multiple matters are flagged as sharing a common trust retainer And each has its own outstanding liabilities as of cut-off And prior refunds or earmarked holds may exist on any linked matter When the calculator runs Then it consolidates trust available across the linked matters and applies each matter’s liabilities as of cut-off And it produces both an overall net refund and a per-matter allocation And it excludes amounts already refunded or on hold to prevent double-refund And it records links to all included matters and balances used
Itemized Breakdown, Reconciliation, and Snapshot Persistence
Given integrations with time/billing, expenses, and trust ledger are connected When the calculator completes Then the sum of fees, costs, taxes, and adjustments equals total liabilities within $0.01 And trust available as of cut-off reconciles to the trust ledger balance report as of cut-off within $0.01 And the system saves a read-only calculation snapshot with timestamp, user, input parameters, and source record IDs And the snapshot is retrievable for the closing statement and audit log
One-Click Refund to Original Method
"As a billing admin, I want to issue refunds back to the original payment method with one click so that clients are reimbursed quickly and we stay aligned with processor and bar rules."
Description

Enables refunds to be initiated with a single action and routed back to the original funding instrument via supported gateways (e.g., LawPay, Stripe, Gravity Legal). Handles partial refunds across multiple source transactions, ACH vs. card rules, over-refund prevention, and gateway webhooks for real-time status updates. Securely uses tokenized payment methods without storing PANs and provides deterministic refund allocation logic for multiple deposits. Exposes clear success/failure states and retry guidance within the CaseSpark UI.

Acceptance Criteria
One-Click Refund at Case Close
Given a case with status "Closed" and a positive refundable trust balance And the user has the "Billing:Refund" permission When the user clicks "Issue Refund" and confirms Then the system initiates a refund to the original funding instrument via the configured gateway and displays a "Refund Pending" state in the case UI And the action is IOLTA-safe: funds are debited from the trust ledger only; the operating ledger is not used And the "Issue Refund" action is disabled if the refundable balance is 0, the case is not eligible, or another refund is in-flight And the confirmation modal shows refund amount, gateway, destination descriptor (e.g., "Original Visa •••• 1234" or "Original ACH"), and the source deposit summary And a unique Refund ID and gateway reference are created and recorded in the audit log
Deterministic Allocation Across Multiple Deposits
Given multiple settled deposits in the trust ledger When a refund amount R is issued Then the allocation algorithm applies FIFO by settlement timestamp across deposits until R is satisfied And each refund component references its source transaction ID and amount And the sum of refund components equals R exactly And un-cleared, on-hold, or chargeback-flagged deposits are excluded from allocation And retries using the same idempotency key produce the identical allocation mapping
Over-Refund Prevention and Concurrency Safety
Given the current refundable balance B When a user attempts to refund an amount A (via one-click full refund or an authorized partial refund entry) Then the system blocks the request if A > B and shows "Amount exceeds refundable balance" And immediately prior to gateway submission, an atomic re-check of available funds is performed; if B has decreased due to a concurrent action, the refund is aborted with an error and no ledger changes occur And the UI updates the displayed refundable balance in real time and removes the refund action when B becomes 0
ACH vs Card Compliance Rules
Given the original funding instrument for a deposit is ACH When a refund is requested Then initiation is permitted only after the gateway marks the ACH deposit as Settled/Cleared; otherwise the action is disabled with guidance And given the original funding instrument is a payment card When a refund is requested Then the refund is sent to the original card within the gateway’s allowable window; if outside the window, the action is blocked with a message to issue an offline refund And for mixed-source refunds, components are routed to their respective original methods (ACH to ACH, card to card)
Gateway API + Webhook Status Synchronization
Given a supported gateway (LawPay, Stripe, Gravity Legal) is configured When a refund is initiated Then the system calls the gateway refund API with an idempotency key, source transaction IDs, and allocation amounts And transient API errors (HTTP 5xx/timeouts) are retried up to 3 times with exponential backoff; the UI displays retry progress and manual retry guidance if retries exhaust And upon receiving webhook events, refund status transitions are updated: Pending -> Succeeded on success; Pending -> Failed on failure, with error reasons captured and shown in the UI And the case UI and ledgers reflect the latest status within 5 seconds of webhook receipt
Security: Tokenized Methods and Audit Logging
Given refund initiation and gateway communication When referencing payment methods Then only tokenized payment identifiers are used; no PANs or bank account numbers are stored or logged by CaseSpark And access is restricted to users with the "Billing:Refund" permission; unauthorized users cannot view or trigger refunds And an immutable audit log records user, timestamp, amount, allocation details, gateway references, status changes, and request origin IP And sensitive values are masked in UI and logs, and exports exclude PAN/ACH numbers
Closing Statement, Receipt, and Ledger Updates
Given a refund transitions to Succeeded When post-processing completes Then a closing statement is generated and attached to the case, detailing refunded amount, allocation by source transaction, remaining trust balance, and ledger entries And a client-facing refund receipt is generated and emailed to the primary client contact; delivery status is recorded And the trust ledger decreases by the refunded amount and the operating ledger remains unchanged; accounting exports reflect the update And if the refund fails, no closing statement or receipt is generated; the UI displays the failure reason and next-step guidance
IOLTA Compliance & Ledger Updates
"As a compliance-minded practitioner, I want the system to enforce IOLTA rules and auto-update ledgers so that every refund is recorded correctly without risking trust violations."
Description

Enforces trust accounting safeguards and automatically posts all refund-related entries to the client trust ledger, matter ledger, and general ledger. Validates cleared funds, prevents negative matter trust balances, blocks commingling, and ensures refunds originate from the trust account when appropriate. Generates linked journal entries (trust disbursement, operating adjustments if needed), attaches reference IDs to processor transactions, and updates running balances to keep three-way reconciliation intact. Displays blocking alerts with remediation steps when compliance checks fail.

Acceptance Criteria
Cleared Funds Validation Before Refund
Given the user initiates a refund from a matter trust balance When any contributing deposit has not settled or is on hold Then the refund action is blocked and an alert states "Uncleared funds" and lists deposit IDs, dates, amounts, and statuses Given all deposits contributing to the refundable balance have settlement status = settled and hold_release_at <= now When the user requests a refund Then the compliance check passes and the refund may proceed to confirmation Given the user retries after the last uncleared deposit settles When the compliance check runs Then the refund is allowed without manual override
Prevent Negative Matter Trust Balance
Given a matter with trust balance B and outstanding holds/encumbrances H When the user enters refund amount R Then the system computes MaxRefund = B - H and blocks if R > MaxRefund with message "Exceeds refundable trust balance; maximum allowed: $MaxRefund" Given R <= MaxRefund When the user confirms the refund Then the post-refund matter trust balance equals B - R and is never negative
Trust Account Source Enforcement (Anti-Commingling)
Given the refund pertains to client trust funds When the user selects a disbursement account not designated as trust Then the action is blocked with message "Refund must be issued from trust account" and the trust account is auto-selected Given the firm has multiple trust accounts by jurisdiction When the refund is initiated for a matter tied to jurisdiction J Then the default disbursement account is the trust account assigned to J and switching to an operating account is blocked Given the refund is for operating overpayment (non-trust) When the user initiates a refund Then the system directs payout from the operating account and blocks selection of a trust account
Automatic Ledger Posting and Three-Way Reconciliation
Given a refund of amount R from trust is successfully executed When postings are created Then the system records: Trust Ledger entry (disbursement, -R), Matter Trust sub-ledger entry (-R), and General Ledger journal [Debit Trust Liability R, Credit Trust Bank Cash R] with matching dates and reference IDs Given postings are recorded When reconciliation runs for the refund date Then bank balance, aggregate client trust ledger, and matter trust sub-ledgers remain equal within $0.01 Given any posting attempt fails atomically When the transaction aborts Then no partial entries remain and balances are unchanged
Processor Linking and Audit Trail
Given a refund is processed via the payment processor When entries are created Then each ledger entry includes ProcessorTransactionID, RefundID, MatterID, ClientID, and UserID Given the audit report is generated for a date range containing the refund When the report is opened Then it shows an immutable trail with before/after balances per ledger, timestamp (UTC), and a checksum of entry content Given an authorized auditor searches by ProcessorTransactionID When the query runs Then all linked entries across trust, matter, and general ledgers are returned within 2 seconds
Blocking Alerts with Remediation
Given any compliance check fails (uncleared funds, negative balance risk, commingling, jurisdiction mismatch) When the user attempts to continue Then a blocking alert lists each failed check with reason and remediation steps Given the alert presents remediation steps When the user clicks a remediation link Then the user is navigated to the relevant screen and can re-run checks without leaving the refund flow Given all failed checks are resolved When the user re-runs compliance checks Then the blocking alert dismisses and the refund workflow proceeds
Closing Statement & Refund Receipt Generation
"As a client, I want a clear closing statement and refund receipt so that I understand exactly what was billed and what I’m getting back."
Description

Automatically produces a branded, itemized closing statement and refund receipt at matter close, detailing fees, costs, taxes, trust inflows/outflows, and the final refund amount. Supports firm branding, PDF export, secure client portal delivery, and localization (currency, date, language). Optionally captures client acknowledgment via e-sign and stores documents within the matter file with immutable references to supporting ledger entries and transaction IDs.

Acceptance Criteria
Automatic Closing Statement and Refund Receipt on Matter Close
Given a matter with finalized fees, costs, taxes, and trust ledger entries including a residual retainer When the user triggers Close Matter with refunds enabled Then the system generates a branded Closing Statement and a Refund Receipt in a single operation And the Closing Statement itemizes fees, costs, taxes, trust inflows and outflows, and displays the computed final refund amount And both documents display firm logo, name, address, and contact details per branding settings And both documents include unique document IDs, generation timestamps, and immutable references to included ledger entry IDs and payment/refund transaction IDs And the Refund Receipt displays the masked original payment method and gateway reference/transaction ID for the refund And the generation process completes within 10 seconds for matters with up to 500 line items
PDF Export and File Integrity
Given the Closing Statement and Refund Receipt have been generated When the user exports/downloads each document as PDF Then each PDF renders with embedded fonts, selectable/searchable text, page numbers, and firm branding elements And each PDF filename follows the pattern {MatterNumber}_{ClientLastName}_{DocumentType}_{YYYY-MM-DD}.pdf And a SHA-256 checksum is stored with the document record for tamper detection And the PDF metadata contains document ID, matter ID, generation timestamp, and locale And re-downloading the same version yields identical checksums
Secure Client Portal Delivery and Access Controls
Given client portal delivery is enabled for the matter and the client has portal access When the user selects Deliver to Portal at matter close Then both documents are published to the client portal with read-only access for designated billing recipients And the client receives a notification containing a secure link without exposing PII in the email body And portal links respect configured expiry and require authentication And an audit log records publication, notification dispatch, access, and downloads with timestamps and user identifiers And if delivery fails, the system surfaces an actionable error, logs the failure, and retains documents in a pending state without marking delivery complete
Localization of Currency, Date, and Language
Given the matter has a specified locale (currency, date format, and language) When the documents are generated Then all monetary amounts are formatted per locale with currency symbol and ISO code, respecting minor units And all dates display in the locale’s date format and time zone And all system labels and headings appear in the selected language And right-to-left languages render correctly with proper text direction while preserving numeric readability And numeric grouping and decimal separators match the locale settings
Optional Client E‑Sign Acknowledgment
Given the firm has enabled client acknowledgment via e-sign for closing documents When the user requests acknowledgment at matter close Then the client is presented with the Closing Statement for signature in the portal And upon signing, the system stores a signed, read-only version with an e-sign certificate including signer identity, timestamp, IP, and hash And the document status updates to Signed and is locked from modification And if the client declines or the request expires, the status reflects Declined or Expired and the matter requires user review before marking fully closed
Matter File Storage, Versioning, and Immutability
Given the documents are generated When they are saved to the matter file Then they are write-protected and associated to the matter with immutable references to supporting ledger entries and transaction IDs And any subsequent re-generation creates a new version with an incremented version number, captured reason, creator, and timestamp And previously generated versions remain retrievable and unchanged And documents are accessible via the matter document list and via API using the document ID And stored checksums are validated on retrieval; any mismatch flags the document as potentially tampered and alerts authorized users
Itemization Accuracy, Balances, and Rounding Rules
Given all invoices, costs, payments, trust inflows, and trust outflows are finalized When the Closing Statement is generated Then line-item subtotals, taxes, and totals reconcile exactly to the displayed grand totals And trust ledger inflows and outflows reconcile to the final trust balance and computed refund amount And monetary values are rounded using the currency’s minor unit and rounding rules configurable by the firm (default: banker’s rounding) And matters with a zero refund generate a Closing Statement without a Refund Receipt and display a zero-refund note And matters with a negative client balance (amount due) generate a Closing Statement showing the amount due and do not generate a Refund Receipt
Jurisdiction-Aware Refund Rules Engine
"As a practice manager, I want refunds to follow jurisdiction-specific trust and tax rules so that our firm remains compliant across all states where we practice."
Description

Applies state bar and jurisdiction-specific rules to refund timing, allowable sources, interest on trust accounts, and tax handling. Maintains a configurable rules library with effective dates and citations, supports firm-level policy overrides within safe bounds, and surfaces jurisdictional warnings or blocks when actions conflict with governing requirements. Integrates with CaseSpark’s jurisdiction metadata on each matter to automatically choose the correct ruleset at close.

Acceptance Criteria
Automatic Ruleset Selection by Jurisdiction and Effective Date
Given a matter with jurisdiction metadata and a close date And the rules library contains one or more active rule versions with effective_from and optional effective_to When the user initiates the refund workflow at case close Then the engine selects the single ruleset whose jurisdiction matches the matter and whose effective period includes the close date (effective_from <= close_date < effective_to or no effective_to) And if multiple candidates exist, the engine selects the one with the latest effective_from within the valid range And if no matching ruleset exists, the refund action is blocked with error code RS-001 and a link to Rules Library And the selected ruleset ID, version, and citations are recorded in the refund audit log
Rules Library Versioning, Citations, and Audit Trail
Given a compliance admin creates or updates jurisdictional rules When saving a ruleset version Then jurisdiction code, effective_from, optional effective_to, citations (at least one), and rule payload sections (timing, sources, interest, tax, severities) are required fields And overlapping effective date ranges for the same jurisdiction are rejected with validation error RL-OVERLAP And prior versions remain immutable; edits result in a new version with a unique ID And deactivation is done by setting effective_to on an existing version; no hard deletes are allowed And every create/update is captured in an audit log with timestamp, actor, change diff, and reason And the library supports export/import of a ruleset version as JSON with checksum verification
Refund Timing Compliance Enforcement
Given the applicable ruleset defines timing constraints (e.g., hold_period, earliest_disbursement_trigger, latest_issue_deadline, calendar_type, timezone) And the matter has relevant trigger dates (e.g., final_invoice_date, payment_settlement_date) When a refund is initiated Then the system computes earliest_allowed_date and latest_allowed_date (if defined) per ruleset, calendar_type, and timezone And if now < earliest_allowed_date, the action is blocked with error TIM-001 and the UI shows the countdown and citation And if latest_allowed_date exists and now > latest_allowed_date, the action is blocked with error TIM-002 and the UI shows remediation guidance and citation And the computed dates and rule references are shown on the closing statement and stored in the audit log
IOLTA-Safe Source Validation and Original Payment Method
Given the ruleset specifies allowable refund sources and routing (e.g., refund_from=trust_only|operating_only|both_with_priority, require_original_payment_method=true|false) And the matter has trust and operating balances and the original payment instrument is on file When the refund amount is calculated at case close Then the system selects funding sources strictly per ruleset priority without causing a negative trust balance or trust-to-operating commingling And if require_original_payment_method=true, the refund is routed to the original instrument; if unavailable and no exception is allowed by rules, the action is blocked with error SRC-001 And if an alternative method is allowed by rules, only permitted options are presented and the selection is logged with reason And all ledger entries (trust, operating, client) are posted atomically with segregation preserved and a reversible journal batch ID is created
Trust Interest Treatment per Jurisdiction
Given the ruleset defines interest handling for trust accounts (IOLTA vs client-specific interest-bearing trust) And the matter trust account type and any accrued interest are known When processing the refund Then for IOLTA accounts, no interest is paid to the client; interest disposition is recorded per rules and cited on the closing statement And for client interest-bearing trust accounts, interest is calculated/refunded per ruleset formula and rounding, with separate ledger postings And any prohibited interest disbursement paths are blocked with error INT-001 and rule citation
Jurisdiction-Specific Tax Handling on Refunds
Given the ruleset defines tax treatment for fees and refunds (taxability, refundable_tax_window, rounding, tax_code) And the original charges include itemized taxable and non-taxable components with recorded tax When a partial or full refund is initiated Then the system computes refundable tax proportionally to the refunded taxable amount and posts reversing entries to the appropriate tax liability accounts using the jurisdiction tax_code And if a refundable_tax_window applies and today is outside the allowed window, the tax refund is blocked with error TAX-001 while the fee refund may proceed if permitted; both outcomes are shown with citations And tax amounts are rounded per rules and displayed on the closing statement and receipt
Firm Policy Overrides and Compliance Warnings/Blocks
Given firm-level override policies are configured And the applicable jurisdiction ruleset is selected When a refund action is evaluated Then the stricter constraint between firm policy and jurisdiction rule is applied And any attempt to weaken a mandatory jurisdiction rule is blocked with error OVR-001 And rule breaches with severity=prohibit result in a hard block; severity=warn require user acknowledgment with reason; severity=inform display a non-blocking notice And all overrides, warnings, and blocks capture user, timestamp, rule/version IDs, decision, and citations in the audit log
Refund Workflow & Role-Based Approvals
"As an operations lead, I want a controlled refund workflow with approvals so that large or complex refunds are reviewed before funds leave the trust account."
Description

Provides a guided close-out workflow initiated from the Matter Close action, including a refundable summary, checklist (e.g., final invoice posted, time entries approved), and one-click refund step. Implements role-based permissions and approval thresholds (e.g., refunds over $5,000 require partner approval), with notifications to approvers and an auditable approval log. Supports draft mode, reason codes, and auto-created tasks for any remediation needed before refund execution.

Acceptance Criteria
Launch Close-Out Workflow from Matter Close
Given a user with access to a Matter and the Matter is active When the user clicks "Close Matter" Then the guided Close-Out workflow opens as a multi-step wizard including the Refund step if a refundable balance exists Given the Matter has no refundable balance When the workflow loads Then the Refund step is marked Not Applicable and the workflow can complete without refund Given the workflow is opened When it loads Then it is context-bound to the originating Matter and displays the Matter ID, client name, and current balances at the top of the wizard
Draft Mode and Reason Codes Requirement
Given the user starts the Close-Out workflow When they click "Save as Draft" Then the full workflow state (inputs, checklist status, computed balances) is saved and is resumable from the Matter within one click Given a refund will be executed When the user attempts to proceed past the Refund step Then a reason code selection is required and persisted to the approval log and refund documents Given a saved draft exists When an authorized user re-opens the workflow Then version history is retained with user, timestamp, and changes visible
Pre-Refund Checklist Enforcement and Remediation Tasks
Given required checklist items (e.g., final invoice posted, time entries approved, expenses reconciled) are defined When any item is unmet Then the workflow blocks progression to the Refund step and lists unmet items with links to resolve Given unmet checklist items exist When the user selects "Create Tasks" Then tasks are auto-created per item with default assignee by role, due date within 3 business days, and deep links back to the item Given all linked tasks are completed in the system When the workflow is refreshed Then the checklist automatically reflects completion and unblocks the Refund step
Refundable Balance Calculation and Summary
Given trust/IOLTA, operating, and AR data are available for the Matter When the workflow loads or a draft is resumed Then the system calculates the refundable amount as residual retainer minus outstanding fees/costs and displays amounts by source account with line-item provenance Given financial entries change after a draft was saved When the draft is resumed Then refund calculations are re-evaluated and any variance from the saved draft is highlighted to the user Given the refundable amount is less than or equal to $0 When viewing the Refund step Then the refund action is disabled and an explanation is displayed
Role-Based Permissions and One-Click Execution
Given role permissions are configured When a user without "Execute Refund" permission opens the Refund step Then they see a read-only view with option to Request Approval but cannot trigger funds movement Given a user with "Execute Refund" permission and all required approvals completed When they click "Refund Now" Then the system initiates a one-click refund to the original payment method and returns a success/failure status within 5 seconds Given a paralegal initiates a refund request When submitted Then it routes for approval per policy before any funds movement occurs
Approval Thresholds, Notifications, and Blocking
Given the organization approval threshold is $5,000 When the refundable amount exceeds $5,000 Then partner approval is required and the refund execution button is blocked until approved Given an approval request is created When it is sent Then approvers receive in-app and email notifications within 1 minute containing Matter ID, amount, reason code, and Approve/Decline actions Given an approver acts on the request When they approve Then the system records the approval with user, timestamp, and optional comment and unblocks refund execution; when they decline, the workflow remains blocked and a remediation task with the decline reason is created
IOLTA-Safe Execution, Ledger Updates, and Documentation
Given a refund executes successfully When the payment gateway confirms Then funds are returned only to the original payment method, trust and operating ledgers are updated with balanced, linked entries, and no co-mingling between trust and operating occurs Given the refund completes When documentation is generated Then a Closing Statement and Refund Receipt PDFs are created, attached to the Matter, include itemization, reason code, approval summary, and last 4 of the payment method, and are sent to the client via configured channel Given a refund attempt fails at the gateway When the failure is returned Then no ledger entries are persisted, the refund status is set to Failed, a retry option is available, and an alert is sent to the initiator
Immutable Audit Trail & Export
"As a compliance officer, I want a complete, tamper-evident audit trail and exports so that I can satisfy audits and investigate any refund in minutes."
Description

Captures an immutable, time-stamped audit log for every refund action, including user, role, before/after balances, journal entries, gateway response payloads, and attached documents. Supports export to CSV/PDF and WORM storage retention settings to satisfy audits and bar inquiries. Provides searchable filters by matter, client, date range, and amount, and exposes reconciliation-friendly reports that tie closing statements to ledger and bank records.

Acceptance Criteria
Audit Log Entry on Refund Execution
Given a confirmed refund is executed for a matter When the refund completes Then an audit entry is appended capturing: refundId, matterId, clientId, userId, userRole, action="refund.executed", timestampUTC (ISO 8601), beforeTrustBalance, afterTrustBalance, beforeOperatingBalance, afterOperatingBalance, journalEntryIds, amount, currency, gatewayTransactionId, gatewayResponseRedacted, attachedDocumentIds (closingStatementId, receiptId) And the audit entry is immutable (no update/delete via UI/API); attempts return 403 and are audit-logged as action="audit.modification.blocked"
Filterable Audit Log Search
Given audit logs exist When a user filters by matter, client, date range (UTC), and amount range Then results include only matching entries, support partial client name matches, and can be sorted by timestamp, amount, or matter And pagination supports page sizes 25, 50, 100 with stable ordering; responses return within 2 seconds for up to 10,000 matching entries
CSV/PDF Export of Audit Logs
Given a set of filtered audit log results When the user exports to CSV Then the file is UTF-8 with headers, includes all visible fields with sensitive values redacted, respects current filters/sort, and is named "audits_YYYYMMDD_HHMMSSZ.csv" When the user exports to PDF Then the PDF contains the same dataset, paginated with timestamp and filter summary footer, and the download begins within 60 seconds for up to 100,000 rows via chunked generation
WORM Retention and Legal Hold
Given an admin sets WORM retention to N years When new audit entries are created Then they are written to WORM storage with retention enforced until expiry; update/delete operations are blocked until expiry When retention settings change Then the change requires dual authorization, is audit-logged, and applies prospectively only When a legal hold is applied Then records under hold are non-deletable post-expiry until the hold is lifted
Reconciliation-Friendly Refund Report
Given refunds occurred in a date range When generating the Refund Reconciliation report Then each row includes: refundId, matterId, clientId, closingStatementId, trustLedgerEntryIds, operatingLedgerEntryIds, bankReference (e.g., ACH trace or payout id), amount, currency, timestampUTC And subtotals by day and matter equal the sum of line items; report total equals ledger delta for the range; mismatches greater than $0.00 are flagged with a variance reason code
Access Control and Audit of Views/Exports
Given role-based access control When a Firm Owner or Accountant views or exports audit logs Then access is granted; Staff without permission receive 403 And every view/export is audit-logged with userId, role, timestampUTC, action, filters, export type; exports are rate-limited to 5 per user per hour and attempts over the limit return 429
Attached Documents Integrity and Retrieval
Given a refund generates a closing statement and receipt When the audit entry is stored Then each attachment is recorded with fileId, filename, byteSize, SHA-256 checksum, and contentType; document links in the audit entry retrieve the correct files And document content is immutable; any regeneration creates a new version with a new documentId linked via version history; prior versions remain readable subject to retention policies

Role Blueprints

Prebuilt, least‑privilege roles tailored to Solo Intake Sprinter, Two‑Partner Orchestrator, After‑Hours Responder, and Conflict Gatekeeper. Assign in one click, then fine‑tune safely. Cuts setup time, removes guesswork, and ensures each teammate sees only what they need to keep intake moving fast without oversharing.

Requirements

Blueprint Catalog (Prebuilt Roles)
"As a firm owner, I want to choose from prebuilt least‑privilege roles that match my practice so that my team is productive quickly without exposing unnecessary client data."
Description

Provide a curated library of prebuilt, least‑privilege role blueprints tailored to Solo Intake Sprinter, Two‑Partner Orchestrator, After‑Hours Responder, and Conflict Gatekeeper. Each blueprint defines granular permissions across CaseSpark modules (Intake Workflows, Conflict Screening, Contacts/Parties, Matter Creation, Jurisdiction‑aware Document Assembly, E‑sign, Communications, and Analytics), with clear data visibility scopes and explicit exclusions to prevent oversharing. Include human‑readable summaries, permission matrices, and searchable metadata to accelerate selection. Surface the catalog in Org Settings and via API for automated provisioning, supporting localization and accessibility. The outcome is faster setup, consistent access controls, and alignment with least‑privilege by default.

Acceptance Criteria
Admin views blueprint catalog in Org Settings
Given I am an Org Admin with "Manage Roles" permission When I navigate to Org Settings > Role Blueprints Then I see exactly four prebuilt blueprints named "Solo Intake Sprinter", "Two‑Partner Orchestrator", "After‑Hours Responder", and "Conflict Gatekeeper" And each blueprint displays a human‑readable summary, a data visibility scope summary, and links to view its permission matrix and explicit exclusions And the catalog first content paint occurs within 2 seconds at p95 and the permission matrix panel opens within 500 ms at p95 And each permission matrix lists all CaseSpark modules (Intake Workflows, Conflict Screening, Contacts/Parties, Matter Creation, Jurisdiction‑aware Document Assembly, E‑sign, Communications, Analytics) with explicit allow/deny per operation and an explicit exclusions section
Client system queries blueprint catalog via API
Given I have a valid API token with scope role.blueprints.read When I GET /v1/role-blueprints?query=conflict&page=1&pageSize=10 Then I receive HTTP 200 with a JSON payload containing only blueprints whose name, tags, modules, or summary match "conflict" And each blueprint object includes fields: id, name, humanSummary, permissionMatrix, exclusions, dataVisibilityScopes, tags, localesSupported And the response includes totalCount and pagination info (page, pageSize) And p95 response time is ≤ 500 ms and the response is cacheable with ETag
Automated provisioning of blueprint to user via API
Given I have a valid API token with scope role.assign.write and an existing userId and blueprintId When I POST /v1/role-assignments with { userId, blueprintId } Then I receive HTTP 201 and the role assignment is created referencing the supplied blueprintId And on immediate GET /v1/users/{userId}/effective-permissions the permissions exactly match the assigned blueprint’s permission matrix and exclusions And a repeat POST with the same { userId, blueprintId } is idempotent and does not create duplicates (returns HTTP 200 with existing assignment)
Least‑privilege enforcement from permission matrix
Given a test user is assigned each prebuilt blueprint When the user attempts any operation not explicitly allowed by that blueprint’s permission matrix Then the UI does not expose the action and the API returns HTTP 403 for direct calls And when the user accesses allowed modules, returned data is restricted to the blueprint’s defined dataVisibilityScopes (e.g., own-intakes, assigned matters) And no records outside the defined scope are returned across search, lists, detail views, exports, or notifications (0 leaks in test dataset)
Search and filter blueprints by metadata
Given I am on Org Settings > Role Blueprints and the catalog is loaded When I search for "after hours" Then only the blueprints whose name, tags, or summary match "after hours" are shown and the match is highlighted When I apply the module filter "Analytics" Then only blueprints whose permission matrix includes any Analytics permission are shown And combining search + filter returns the intersection of results And clearing search and filters restores the full set of four blueprints
Localization and accessibility of blueprint catalog
Given my profile locale is es-ES When I open Org Settings > Role Blueprints Then blueprint names and summaries are displayed in Spanish and date/number formats respect locale And switching locale to en-US updates the text accordingly And the catalog and permission matrix are fully usable with keyboard only (tab order logical, focus visible) and meet WCAG 2.1 AA (contrast ≥ 4.5:1, non-color indicators, accessible table semantics with headers announced by screen readers)
One‑Click Role Assignment & Bulk Apply
"As an admin, I want to assign recommended roles to my team in one click so that I can configure access correctly without tedious manual permission setup."
Description

Enable assignment of a selected blueprint to one or many users in a single action from Org Settings, onboarding flows, directory sync, or API. Provide conflict detection against existing custom permissions, with guided resolution (auto‑revoke superseded permissions, preserve required dependencies) and a reversible bulk change (undo/rollback). Support mapping rules (e.g., After‑Hours Responder for on‑call group) and CSV import. Emit events for notifications and audits. This removes manual toggling, reduces errors, and shortens time‑to‑value.

Acceptance Criteria
One-Click Assign Blueprint to Single User from Org Settings
Given an Org Admin selects the "Solo Intake Sprinter" blueprint on Org Settings > Roles. When the admin clicks "Assign" for a specific user and confirms. Then the user's effective permissions match the blueprint's least-privilege set exactly, except required dependencies are preserved. And any pre-existing custom permissions that are superseded by the blueprint are revoked automatically. And a success message shows the user name and total permissions added/removed. And an audit event "role.blueprint.assigned" is emitted with actorId, userId, blueprintId, deltaCounts, correlationId, timestamp. And the user's access reflects the new permissions on next navigation without requiring logout.
Bulk Apply Blueprint to Multiple Users with Undo
Given an Org Admin selects multiple users (e.g., 5) and the "After-Hours Responder" blueprint on Org Settings > Roles. When the admin clicks "Bulk Apply" and confirms. Then a bulk job is created and displayed with a progress indicator. And for N ≤ 50 users, the job completes within 30 seconds under normal load. And the results list per-user status (Success, Skipped, Failed) and counts of permissions added/removed. And an "Undo" action is available for this job for 24 hours. When the admin clicks "Undo" and confirms. Then the system restores each affected user's prior permissions snapshot where unchanged since the job; any conflicts are reported as "Could not fully undo" with reasons. And corresponding audit events "role.bulk.apply" and "role.bulk.undo" are recorded with correlationId.
Guided Conflict Detection and Resolution Wizard
Given selected users have custom permissions that overlap or exceed the target blueprint. When the admin launches the Guided Resolution wizard during assignment. Then the wizard displays a per-user diff of permissions to add, revoke, and keep (dependencies). And the admin can choose Auto-resolve, Preserve extras, or Skip per user or apply to all. And choosing Auto-resolve revokes only superseded extras while preserving dependencies required for assigned permissions. And the final confirmation screen shows exact counts to be changed and no unresolved dependency errors. And the applied results match the preview exactly.
Mapping Rules: Auto-Assign After-Hours Responder to On-Call Group
Given a mapping rule "On-Call Group → After-Hours Responder blueprint" is enabled. When a user is added to the "On-Call" group via directory sync or UI. Then the blueprint is assigned to that user within 2 minutes and an "auto" source is recorded. When the user is removed from the group. Then the blueprint is removed within 2 minutes unless the user has a manual assignment override, in which case it is retained. And audit events "role.mapping.apply" and "role.mapping.remove" include groupId, userId, blueprintId, mappingRuleId, and correlationId. And repeated group changes do not create duplicate assignments (idempotent).
CSV Import with Preview and Error Handling
Given an Org Admin uploads a CSV with headers user_email, blueprint_key, action (assign|remove). When the file is parsed. Then invalid rows are rejected with row numbers and reasons; valid rows are preserved. And a preview shows counts to assign/remove/skip and per-row diffs before any changes occur. When the admin confirms "Apply". Then only valid rows are executed; the system processes up to 500 rows per upload. And a single bulk job id is created with per-row outcomes and an available Undo for 24 hours. And an audit event "role.csv.apply" is recorded with file checksum and counts.
API and Directory Sync Assignment with Events
Given an authenticated integration calls POST /api/role-assignments with blueprintId and userIds, including Idempotency-Key. When the request is accepted. Then the API responds 202 with jobId and the job is visible in the Activity Log. And retries with the same Idempotency-Key do not duplicate changes. And GET /api/role-assignments/jobs/{jobId} returns per-user results and counts. And a webhook event "role.assignment.completed" is delivered to subscribed endpoints with signature and correlationId within 5 seconds of completion. And SCIM/directory sync assignments trigger the same audit and event flows.
Notifications and Audit Trail for Role Assignment Actions
Given any role assignment action is completed (single, bulk, mapping, CSV, API). When the job reaches a terminal state (Completed or Completed with errors). Then the initiating actor receives an in-app notification and an email summary with counts and a link to details. And the Audit Log records the action with actor, orgId, blueprintId, impacted user count, delta counts, start/end timestamps, and outcome. And all events include correlationId and are queryable by date range and actor within 1 minute of completion.
Safe Fine‑Tuning with Guardrails
"As an admin, I want to fine‑tune a role blueprint safely so that I can tailor access to my firm’s needs without violating least‑privilege or creating workflow gaps."
Description

Provide a guided editor to customize blueprint permissions while enforcing least‑privilege guardrails and dependency rules (e.g., cannot grant export without view; cannot edit without list access). Highlight deviations from the baseline blueprint, show a diff view, and calculate a risk score with warnings for sensitive scopes (PII fields, financial data, document export, cross‑matter search). Offer one‑tap reversion to defaults and draft mode to test changes before publish. Integrate with policy checks to prevent unsafe combinations. This enables tailored access without accidental oversharing or broken workflows.

Acceptance Criteria
Dependency Guardrails Enforcement in Editor
Given a role draft where 'View Documents' is disabled When the user toggles 'Export Documents' on Then the system displays a dependency notice and automatically enables 'View Documents' in the draft And the change appears in the diff as 'Export Documents: added' and 'View Documents: added' And the user cannot publish until acknowledging the dependency change Given a role draft where 'List Cases' is disabled When the user toggles 'Edit Case' on Then the system blocks the toggle and shows an inline error 'Requires List Cases' And the toggle remains off until 'List Cases' is enabled
Real-Time Risk Scoring and Sensitive Scope Warnings
Given the editor is open on a role draft When any permission is toggled Then the risk score (0–100) recalculates within 300 ms and displays the level as Low/Medium/High Given a user enables any of: 'PII Fields', 'Financial Data', 'Document Export', or 'Cross‑Matter Search' When the change is applied Then a warning badge appears next to the scope and in the risk panel listing the new sensitive scopes contributing to risk Given the risk score is High (>= 70) When the user attempts to publish Then a confirmation modal lists risk drivers for awareness and the publish action remains available unless policy checks fail
Baseline Diff View and Deviation Highlighting
Given a role blueprint baseline and a modified draft When the user opens Diff View Then only changed permissions are shown, grouped by resource with 'added', 'removed', or 'tightened/loosened' labels Given there are deviations When Diff View loads Then a deviation count is displayed and matches the number of changed permissions Given the user clicks a deviation item When the editor view opens Then the corresponding permission is scrolled into view and highlighted
One‑Tap Reversion to Blueprint Defaults
Given a modified draft with at least one deviation from baseline When the user clicks 'Revert to Blueprint' Then a confirmation dialog appears summarizing the number of changes to be discarded Given the user confirms reversion When the action completes Then the draft permissions exactly match the baseline, deviation count is zero, and risk score matches the baseline risk Given the draft already matches the baseline When the user clicks 'Revert to Blueprint' Then the action is disabled with tooltip 'No changes to revert'
Draft Mode Preview and Safe Testing
Given a role draft with unpublished changes When the user clicks 'Preview as Role' Then a sandbox session starts applying the draft permissions to the user's view without altering production roles Given the user is in preview When attempting actions not permitted by the draft Then access is denied with 'Preview restriction' messaging and no writes occur to production data Given the user exits preview When returning to the editor Then all preview sessions are terminated and no preview changes persist outside the sandbox
Policy Checks Blocking Unsafe Permission Combinations
Given a draft includes both 'Document Export' and 'Cross‑Matter Search' When the user attempts to publish Then publish is blocked with an error 'Unsafe combination per policy RS‑101' and a 'Fix' option that disables one or both scopes Given a draft attempts to enable 'Edit PII Fields' without 'View PII Fields' When saving or publishing Then the system blocks the action and surfaces the dependency/policy rule ID and resolution steps Given all policy checks pass When the user clicks Publish Then the role is published successfully and a policy check audit record is created with status 'pass'
Access Preview Simulator (View As)
"As a security‑conscious partner, I want to preview what a role can see and do so that I can validate access is correct before assigning it firm‑wide."
Description

Allow administrators to preview the product as any user or role, rendering UI, lists, fields, documents, and actions exactly as that persona would see them, using masked or synthetic data where appropriate. Provide module‑by‑module previews (Intake, Conflicts, Documents, E‑sign, Messaging) and highlight items hidden due to permissions with explanations. Offer quick links from the preview to adjust the specific permission responsible. Read‑only, non‑destructive, and auditable. This validates least‑privilege before broad rollout and reduces back‑and‑forth with users.

Acceptance Criteria
Preview as Role Blueprint: Solo Intake Sprinter
Given I am an administrator with permission to use View As And the role blueprint "Solo Intake Sprinter" exists When I select View As and choose the role "Solo Intake Sprinter" Then the application re-renders within 2 seconds to match that role’s effective permissions And navigation, lists, fields, documents, and actions exactly match what a user assigned only that role would see And no capabilities outside that role are visible or executable And a persistent banner displays "Previewing as: Solo Intake Sprinter (read-only)" until I exit preview
Module Toggle Preview (Intake, Conflicts, Documents, E‑sign, Messaging)
Given I am in View As mode When I select only Conflicts and Documents in the module picker Then only those modules are visible in navigation and UI surfaces And non-selected modules are hidden from view and search results And permission scopes inside the selected modules are enforced as they would be for the target persona And switching the module selection updates the UI in under 1 second without a full page reload And exiting View As returns me to my normal admin view
Hidden Items Highlight with Permission Explanations
Given I am in View As mode within a list or record view When an item, field, section, or action is hidden due to permissions Then a non-revealing indicator shows the count of hidden elements (e.g., "3 items hidden") And an explanation panel reveals the controlling permission(s) and source (Role Blueprint or custom override) without exposing underlying sensitive data And the explanation includes a human-readable rule name and system key And I can export a summary of hidden elements and reasons for the current page
Quick Link to Adjust Specific Permission
Given I am viewing a permission explanation in View As When I click "Adjust Permission" Then the Permissions Editor opens in a new tab focused on the exact permission and pre-selected role/user context And after I save a change, I can refresh the preview tab and see the effect reflected within 2 seconds And the permission change is audited with who, what, when, and a link back to the originating preview session
Read‑Only and Non‑Destructive Preview Safeguards
Given I am in View As mode When I attempt any write action (create, edit, delete, send e‑sign, send message, upload, annotate) Then the control is disabled or intercepted with a message "Preview is read-only" And no POST, PUT, PATCH, or DELETE requests are sent to backend APIs for the attempted action And no emails, SMS, e‑sign invitations, or webhooks are dispatched And the blocked attempt is logged as a preview interaction without altering any production data
Masked and Synthetic Data Rendering in Preview
Given I am in View As mode and viewing records containing PII or privileged content When fields and documents render Then PII fields (e.g., SSN, DOB, phone, email, address) are masked per masking policy And privileged/sensitive documents render redacted previews or synthetic placeholders rather than originals And there is no control to unmask data while in View As And masking rules are configurable per field and applied consistently across all modules and lists
Audit Trail of View As Sessions
Given a View As session is started When the session begins and ends Then an audit log records admin identity, target user/role, modules selected, timestamps, duration, client IP, and user agent And blocked action attempts and permission-adjustment links clicked are recorded with contextual references And security administrators can search, filter, and export these logs in real time (available within 5 seconds of events) And log retention is configurable (90 days to 7 years) and logs are tamper-evident and immutable to non-security roles
Conflict Data Segmentation & Field‑Level Controls
"As a conflict gatekeeper, I want access to conflict screening data without seeing unrelated matter details so that I can perform accurate checks while protecting client confidentiality."
Description

Implement record‑ and field‑level access controls that segregate conflict screening artifacts (party indexes, relationships, conflict hits) from confidential matter details. Ensure the Conflict Gatekeeper can run screens, view results, and manage conflicts without access to unrelated matter notes, documents, or financials. Introduce sensitive‑field tagging (addresses, SSNs, financial disclosures) and scoped visibility per blueprint. Integrate with jurisdiction‑aware search so results respect role scopes. Provide redaction-on‑demand for shared artifacts. This preserves confidentiality while enabling rapid, accurate conflict checks.

Acceptance Criteria
Gatekeeper Conflict Screen Without Matter Access
Given a user with the Conflict Gatekeeper role and no explicit matter permissions When they run a conflict screen on a new intake Then they can execute the search and view party indexes, relationships, and conflict hits, and no matter notes, documents, tasks, or financials are visible in the UI And direct navigation (deep link) or API calls to matter notes, documents, tasks, or financials return 403 Forbidden and are logged And converting the intake to a matter does not expand the Gatekeeper’s access beyond the conflict module unless an admin grants additional permissions
Sensitive Field Tagging and Field‑Level Visibility by Blueprint
Given fields tagged as Sensitive (SSN, Address, Financial Disclosure) When a user with the Conflict Gatekeeper role views records Then SSN is masked to last 4 digits, Address is limited to city and state, and Financial Disclosure fields are hidden When a user with the Solo Intake Sprinter role views records Then Address is fully visible, SSN is masked to last 4 digits, and Financial Disclosure is visible only if Consent=True on the record When a user with the After‑Hours Responder role views records Then SSN is hidden, Address is limited to city and state, and Financial Disclosure is hidden And sensitive fields the role cannot see are excluded from exports, webhooks, and API responses (returned as null or redacted tokens)
Jurisdiction‑Aware Conflict Search Respects Role Scopes
Given a firm with matters and parties in CA and TX and a Conflict Gatekeeper scoped to CA only When the Gatekeeper runs a jurisdiction‑aware conflict search Then results, counts, and facets include only CA records; TX records are excluded from the UI and API And attempts to filter by or expand to TX return no data and are logged as blocked by role jurisdiction scope And scheduled or saved searches execute with the same scope enforcement
Redaction‑On‑Demand for Shared Conflict Artifacts
Given a conflict hit report containing sensitive fields When a user exports or shares the report with Redact Sensitive Fields enabled Then the generated artifact (PDF/HTML/share link) masks SSN to ***‑**‑XXXX, truncates addresses to city/state, removes financial disclosure details, and omits attachments/notes not permitted to the recipient’s role And the artifact includes a visible “Redacted” watermark and a generated audit reference ID And the share link enforces the recipient’s current role permissions at access time and expires according to the configured TTL
Record‑ and Field‑Level Access Auditability
Given any read or write attempt to conflict artifacts or confidential matter fields When the request is evaluated by the access layer (UI or API) Then an audit entry is recorded with timestamp, actor ID, role blueprint, resource type/ID, fields accessed, jurisdiction, decision (Allow/Deny), channel (UI/API), and request origin (IP/User‑Agent) And denied events include the specific policy reason (e.g., FieldSensitive.SSN:HiddenByRole, JurisdictionScope:TX) And audit logs are immutable, queryable by filters, and exportable with sensitive values redacted per viewer’s permissions
Blueprint Assignment and Safe Fine‑Tuning Guards
Given an admin assigns the Conflict Gatekeeper role blueprint to a user When the assignment is saved Then the user receives access only to the conflict module and explicitly allowed fields, and is denied matter notes, documents, tasks, and financials by default When the admin attempts to fine‑tune permissions to expose any confidential matter detail to the Gatekeeper Then the system presents a change impact diff, requires justification, records an auditable change entry, and blocks changes that violate the conflict‑data segregation guardrail policy And a “Preview as Role” test shows exactly which records and fields will be visible after changes
Immutable Audit Trails & Change Approvals
"As a managing partner, I want a complete, immutable history of role changes and approvals so that I can demonstrate compliance and investigate access issues quickly."
Description

Record every role assignment, permission change, and blueprint modification with actor, timestamp, IP/device, and before/after diffs. Provide searchable, exportable logs (CSV/JSON) with retention settings and webhook/SIEM integrations. Support optional approval workflows for high‑risk permission grants, with notifications to owners and dual‑control for sensitive scopes (e.g., document export, cross‑matter search). Expose per‑user access history to accelerate investigations. This delivers compliance evidence and operational accountability.

Acceptance Criteria
Event Coverage & Required Fields
Given a role is assigned/removed, a permission is granted/revoked, or a role blueprint is created/updated/deleted, When the action is committed, Then an audit event is recorded with fields: event_id, action_type, actor_user_id, actor_email, target_user_id, target_role_id/permission_key/blueprint_id, timestamp (UTC ISO 8601 with ms), actor_ip, actor_device (user agent), request_id, before_value (JSON), after_value (JSON), diff (JSON Patch), outcome (success|failure). Given the action completes, When querying by request_id, Then exactly one event per action is returned (no duplicates). Given the action completes, Then the event is visible in UI search and API within 5 seconds of commit.
Immutability & Tamper Resistance
Given any authenticated user (including org owners/admins), When attempting to update or delete an audit event via UI or API, Then the request is rejected with HTTP 403 and a tamper_attempt audit event is recorded. Given application endpoints, Then no PUT/PATCH/DELETE methods exist for /audit/events and only INSERT is permitted at the application layer. Given retention has not elapsed, When an admin attempts any manual purge, Then the option is unavailable; only scheduled retention jobs can remove events and a purge_summary audit event is recorded when they do.
Search, Filter, Pagination & Export (CSV/JSON)
Given ≥50,000 audit events exist, When filtering by any combination of actor, action_type, target_user_id, IP, date range, and outcome, Then results are correct, sorted by timestamp desc by default, and the first 100 results return in ≤2 seconds. Given a free-text query "blueprint", When executed, Then events whose action_type or diff/values contain the term are returned. Given pagination via cursor or page/page_size (max 1000), Then total count and navigation cursors/links are accurate and stable for 10 minutes. Given a filtered result set ≤100,000 events, When exporting, Then CSV and JSON exports include all selected events and fields; CSV is UTF-8 RFC4180 with header row; JSON is an array of objects; the export is ready within 60 seconds and includes metadata (exported_at, filter_params, record_count, checksum).
Configurable Retention Settings
Given an org owner sets retention to 365 days, When saved, Then events older than 365 days are purged within 24 hours and are no longer retrievable via UI, API, or export. Given retention is decreased, When saving, Then a confirmation modal shows the projected deletion count and cutoff date and requires explicit confirmation to proceed. Given a retention purge runs, Then a retention_purge audit event is recorded with cutoff date, counts purged, and job id.
Webhook & SIEM Integrations
Given a webhook URL and auth header are configured, When an audit event of the covered types is created, Then the system POSTs the JSON payload over HTTPS within 5 seconds and marks delivery success on any 2xx response. Given network or 5xx errors, Then deliveries are retried with exponential backoff for up to 24 hours; events include an idempotent event_id to enable deduplication downstream. Given a 4xx (except 429) response, Then the endpoint is placed in a dead-letter state, owners are notified, and re-enable/retry can be triggered from the UI. Given SIEM integration is enabled, Then payloads conform to documented schema and appear at the destination within 60 seconds under normal network conditions; failures generate owner notifications and are logged in a delivery history view.
Dual-Control Approval for Sensitive Grants
Given a user requests to grant a sensitive scope (document_export or cross_matter_search), When submitted, Then the change enters Pending and is not effective until approved by a second approver who is not the requester. Then a justification field (min 10 characters) is required; owners receive email and in-app notifications immediately and daily until resolution or timeout. Given an approver approves or rejects, Then the decision is applied, all stakeholders are notified, and an approval_decision audit event is recorded with approver id, timestamp, decision, and justification. Given 7 days elapse without approval, Then the request auto-expires, is not applied, and expiration notifications are sent.
Per-User Access History View
Given an investigator opens a user's Access History for the last 90 days, Then the timeline lists that user's role assignments/removals, permission grants/revokes, and high-risk approval requests/decisions with actor, timestamp, IP/device, and links to related matters. Given filters (date range, action_type, IP) are applied, Then results update correctly and can be exported to CSV/JSON with the same fields. Given the user has ≥10,000 related events, Then the first page loads in ≤3 seconds and supports pagination without timeouts.
Blueprint Versioning & Safe Updates
"As an admin, I want to update role blueprints safely without losing our customizations so that we stay secure and aligned with new product capabilities."
Description

Version each blueprint with semantic versions and maintain change logs describing added/removed permissions and scope adjustments. When a new version is available, provide guided updates with impact analysis, a test sandbox, and policy checks to ensure firm‑specific deviations are preserved or explicitly reconciled. Allow firms to pin to a version, opt into auto‑updates with safeguards, and roll back if issues arise. Expose version diffs via UI and API for transparency. This keeps roles current with product evolution without disrupting customized access models.

Acceptance Criteria
Semantic Versioning & Change Logs
Given an admin views a role blueprint, when the blueprint version is released, then its version follows semantic format X.Y.Z and increments based on change type (MAJOR for breaking removals/tightening, MINOR for additive non-breaking changes, PATCH for metadata/documentation only). And a change log entry is generated listing addedPermissions[], removedPermissions[], scopeAdjustments[], rationale, timestamp, and actor. And the change log is visible in the UI and retrievable via API at /blueprints/{id}/versions and is immutable once published.
Guided Update Preserves Firm Deviations
Given a firm has customized a blueprint on version V, when a newer version V′ is available, then the update wizard shows a side-by-side diff of V vs V′ overlaid with firm-specific overrides. And for each conflict, the wizard requires a choice (keep firm override, accept blueprint change, or merge) before continuing. And after applying, all non-conflicting firm deviations remain intact, chosen reconciliations are applied, and a summary report of preserved/changed permissions is generated.
Sandbox Test of Blueprint Updates
Given an available blueprint update, when the admin selects "Test in Sandbox", then the system creates an isolated sandbox copy of the firm’s role configuration and applies the update only in the sandbox. And the sandbox supports simulating user assignments and producing an access diff report per user (resources gained/lost) before commit. And no production permissions change until the admin confirms "Apply to Production"; sandbox can be discarded without side effects.
Version Pinning & Auto-Update Safeguards
Given an admin pins a blueprint to version X.Y.Z, when auto-update runs, then no updates are applied beyond X.Y.Z until unpinned. And if auto-update is enabled with a policy (PATCH-only or MINOR+PATCH; MAJOR excluded), then only qualifying versions are applied within the configured maintenance window after passing policy checks. And admins receive notifications for pending and completed auto-updates; all actions are recorded in the audit log.
Rollback to Previous Version
Given a blueprint update has been applied, when the admin initiates a rollback, then the system restores the immediately previous version and reverts effective permissions for affected users to the prior state. And if rollback would violate the current permission schema, the system blocks it and presents required remediation steps to proceed. And the system records rollback actions and provides downloadable pre/post access diffs.
UI & API Version Diff Transparency
Given an admin inspects a blueprint update, when viewing Version Diff, then the UI enumerates addedPermissions, removedPermissions, and scopeAdjustments with counts and labels. And the API exposes GET /blueprints/{id}/diff?from=X&to=Y returning structured JSON including addedPermissions[], removedPermissions[], scopeAdjustments[], breakingChanges[], and metadata. And diffs are filterable by permission type/scope and exportable as CSV and JSON.
Pre-Update Policy Checks & Approval
Given firm policy rules are configured, when an update is proposed (manual or auto), then the system evaluates least-privilege deltas, prohibited-resource lists, and separation-of-duties constraints, classifying results as Blocker or Warning. And updates with Blockers cannot proceed without resolution or explicit authorized override; Warnings require acknowledgement. And the approval workflow supports at least two approvers, records decisions with timestamps, and links approvals to the specific version diff.

Field Masking

Granular, field‑level controls to hide sensitive PII (SSN, DOB, addresses, payment data) by default with partial reveals (e.g., last‑4). Masked values flow through intake and documents without exposing full details. Reduces risk while preserving speed so staff can qualify leads and assemble filings confidently.

Requirements

Default PII Masking Policy Engine
"As an office admin, I want to enforce default masking for sensitive fields so that staff never see full PII during intake unless explicitly authorized."
Description

Implement server-enforced, tenant-configurable default masking for sensitive fields (e.g., SSN, DOB, full address, payment details) at capture, storage, and display. Provide a rule engine with predefined family-law templates, regex/type-based detectors, and deny-by-default behavior when rules are missing or ambiguous. Ensure masked values are the default representation in all UI components and APIs, and that stored values are encrypted at rest. Include migration utilities to tag and mask existing data fields. The outcome is a consistent, fail-safe baseline that minimizes accidental exposure while preserving data integrity for downstream processes.

Acceptance Criteria
Default masking across UI and API at data capture
Given tenant A has Default PII Masking Policy enabled And a user submits SSN 123-45-6789, DOB 03/14/1980, Street "123 Main St", and Card 4111111111111111 When the record is saved and subsequently retrieved in any UI list, detail view, or form field Then SSN is displayed as ***-**-6789 by default And DOB is displayed as 1980 (year only) by default And Street Address line is displayed as **** while city, state, and ZIP remain visible And Payment card is displayed as **** **** **** 1111 And no UI component displays the full values by default And all read API responses for these fields return only the masked representations by default
Encryption at rest for sensitive fields
Given sensitive fields (SSN, DOB, Street Address line, Payment PAN) are persisted When inspecting data at rest in the primary database and backups Then the values are encrypted and not readable in plaintext And encryption keys are managed in a KMS separate from the data plane And rotating the active KMS key preserves data access without data loss And search indexes and caches do not contain plaintext for these fields
Tenant-configurable masking rules and templates
Given an admin opens Masking Policy settings When the admin applies the "Family Law Default" template Then rules for SSN, DOB, Address, and Payment are created with deny-by-default enabled And the admin can override a field rule (e.g., DOB display set to year-only) And rule validation prevents saving invalid regex or conflicting precedence And changes take effect for new and existing reads within 60 seconds of save And detectors auto-tag fields matching SSN/DOB/PAN patterns in custom forms
Deny-by-default on missing or ambiguous rules
Given a new custom field named "Client Tax Number" is added without an explicit rule When data is captured for this field and later read through UI or API Then the field is treated as sensitive and displayed masked by default And API responses return only masked values for the field by default And any request for an unmasked value without an explicit allow rule is blocked with HTTP 403 and error code MASKING_POLICY_ENFORCED And an audit event is recorded indicating deny-by-default was applied
Partial reveal controls with standardized formats
Given masked fields are displayed by default When an authorized user requests a partial reveal for SSN or Payment Then only the last-4 digits are revealed and the remainder stays masked And the partial reveal is session-bound and reverts to masked on refresh or timeout And DOB partial reveal displays year-only; full DOB is not shown via partial reveal And Address partial reveal shows city, state, and ZIP but not street line And APIs support partial reveals only via an explicit parameter (e.g., mask=partial); full values are never returned by default
Backfill and migration of existing PII
Given existing records contain untagged or unmasked PII When the migration utility is executed in dry-run mode Then it outputs a report listing targeted fields, counts, and sample masked formats without changing data When the migration is executed in apply mode Then targeted fields are tagged and masked without data loss And the process is idempotent and resumable after interruption And a backup snapshot is created before changes And post-migration verification finds no plaintext PII in UI or API reads
Downstream processing preserves integrity while masking outputs
Given full values are stored for SSN, DOB, Address, and Payment When generating documents and rendering UI previews Then internal processors receive full values to ensure correct calculations and formatting And UI previews, activity feeds, and notifications display only masked representations And generated documents include full or partial values according to the configured masking rule for that output channel And round-trip tests confirm masked display does not modify or corrupt the stored full value
Granular Role- and Context-Based Reveal Controls
"As a managing attorney, I want reveals gated by role, MFA, and case context so that only authorized staff can view full PII when necessary."
Description

Provide fine-grained controls that gate per-field reveals by user role (attorney, paralegal, intake), matter ownership, and workflow stage. Requires explicit reveal actions, time-bound viewing windows, optional MFA challenge, and mandatory reason capture. Support configurable cooldowns, rate limits, and deny-by-default rules. Respect least-privilege principles and integrate with existing RBAC groups and user directory. The outcome ensures only appropriately authorized users can access full values when operationally necessary.

Acceptance Criteria
Role- and Matter-Based Reveal Authorization
Given a user is authenticated via SSO and mapped to RBAC groups from the directory When their role includes reveal permission for Field X and they are assigned to Matter M Then a reveal request for Field X on Matter M is approved and the full value is displayed Given the same user loses Matter M assignment or role mapping When they attempt a reveal after the change Then the request is denied within 60 seconds with error code REVEAL_FORBIDDEN and the value remains masked Given a field has no explicit reveal policy configured When any user attempts to reveal it Then the attempt is denied by default and a configuration alert is raised for administrators
Workflow Stage-Gated Reveal
Given Matter M is in Intake stage When a Paralegal attempts to reveal a DOB field Then the request is denied until Matter M reaches Verification stage or higher per policy Given Matter M transitions to Filing stage When the same user attempts the reveal within 60 seconds of the transition Then the system reevaluates stage context and allows the reveal if permitted by policy Given Matter M regresses from Filing to Intake while a reveal window is open When the stage change is processed Then the value is immediately remasked and further reveals are blocked until stage policy allows
Explicit Reveal Action with Reason Capture and Audit
Given a masked SSN field is displayed When the user clicks Reveal and provides a reason (category selected and free-text justification of at least 10 characters) Then the request proceeds; otherwise the Reveal action is disabled and the API returns 400 on missing/invalid reason Given a reveal decision (approved or denied) is made When the event is finalized Then an immutable audit entry is recorded with userId, role, fieldId, matterId, timestamp, IP, userAgent, workflowStage, reasonCategory, reasonText, decision, and configured retention metadata
Time-Bound Reveal Window with Auto-Remask
Given policy revealDuration is set to 120 seconds When a reveal is approved at time T0 Then the full value is visible only until T0+120s and auto-remasks without user action thereafter Given the browser tab loses focus or the session is idle for more than 30 seconds during an active reveal window When inactivity is detected Then the value is immediately remasked and the remaining reveal time is forfeited Given the user attempts to extend visibility by reloading or navigating within the app during an active window When the page loads Then the window is not extended; a new reveal requires a new approved request
Optional MFA Challenge on Sensitive Fields
Given Field SSN has sensitivity High and the user’s role policy requires MFA for reveals When the user initiates a reveal Then a second factor challenge (TOTP, push, or WebAuthn) is required and must succeed within 60 seconds before the reveal is granted Given the user successfully completed MFA for a High sensitivity reveal within the past 10 minutes When they initiate another reveal of a High sensitivity field Then MFA is skipped per policy grace period and the event references the prior MFA assertion Given the user fails MFA 3 consecutive times within 10 minutes When they attempt additional High sensitivity reveals Then reveals are blocked for 15 minutes with error REVEAL_MFA_LOCKOUT and security admins are notified
Reveal Rate Limiting and Cooldown Enforcement
Given policy rateLimit is 5 reveal approvals per user across High sensitivity fields per 60-minute window When a 6th reveal attempt occurs within the same window Then the system blocks the attempt with error REVEAL_RATE_LIMITED and returns the remaining wait time in seconds Given policy cooldown is 10 minutes per field per user When a user attempts to reveal the same field within 10 minutes of a successful reveal Then the attempt is blocked with error COOLDOWN_ACTIVE and the remaining cooldown is displayed Given the rate-limit window expires or cooldown elapses When the next reveal attempt occurs Then counters reset as expected and the reveal proceeds if other policies allow
Downstream Systems Respect Reveal Scope and Masking
Given a document assembly job runs without an active, valid reveal token for Field X for the requesting user When the document is generated Then only a masked or partial value (e.g., last-4) is inserted and no full value is written to document artifacts, previews, or logs Given an active reveal token with remaining duration for Field X and policy permits unmasked output at the current workflow stage and role When the document is generated Then the full value is inserted and the audit log links the revealId to the documentId and jobId Given a CSV export is requested by a user without unmask export permission When the export runs Then all sensitive fields remain masked and export processes cannot elevate privileges by passing a reveal token
Partial Reveal Modes and Redaction Formats
"As an intake specialist, I want partial reveals like SSN last-4 and DOB month/year so that I can qualify clients without exposing full details."
Description

Offer configurable partial reveal modes per field type, such as SSN last-4, payment PAN first-6/last-4, DOB month/year or derived age, address city/state without street, and masked email local parts. Enforce consistent formatting across UI, exports, PDFs, and e-sign previews. Validate input/output to prevent accidental full exposure through formatting or concatenation. The outcome preserves operational speed—allowing staff to qualify leads and verify identities—without disclosing full sensitive values.

Acceptance Criteria
SSN Last-4 Reveal Across Surfaces
Given a client record contains a valid SSN and SSN masking mode is "last-4" and the user does not have "View Full SSN" permission When the intake form, client profile, list views, CSV export, generated PDF, and e-sign preview render the SSN Then the rendered value is ***-**-#### showing only the last four digits with hyphenated format and never displays the first five digits And copying, printing, or tooltip preview of the SSN shows only the masked value And attempted field-level "Reveal" control is disabled for unauthorized users Given a user with "Reveal SSN Last-4" permission When pressing Reveal on the SSN field Then the view shows only the last-4 (no additional digits), auto-reverts to masked on blur or after 60 seconds, and the reveal event is timestamped in the audit log
Payment PAN First-6/Last-4 Masking With Anti-Concatenation
Given a stored primary account number (PAN) and PAN masking mode is "first-6/last-4" When the PAN renders in UI, CSV export, PDF, and e-sign preview Then exactly the first 6 and last 4 digits are unmasked, the middle digits are replaced by the same count of • characters, and the total count of unmasked digits does not exceed 10 on any surface And copying or exporting the field preserves the mask characters; no surface provides more than 10 unmasked digits Given a template or script attempts to concatenate multiple masked PAN fragments or format tokens When the output would result in more than 10 unmasked digits or the full PAN length Then the system replaces the output with a fully redacted token (e.g., [PAN-REDACTED]) and records a validation error in logs without emitting the sensitive value
DOB Month/Year and Derived Age Modes
Given a stored date of birth (DOB) and masking mode is "Month/Year" When the DOB renders across UI, CSV, PDF, and e-sign preview Then the value is formatted as MM/YYYY and the day component is never displayed or inferable from adjacent text Given the masking mode is "Derived Age" When the DOB renders Then the value displays as Age N computed from the DOB and current date with correct boundary handling on the birthday and leap years, and the raw DOB is not displayed
Address City/State-Only Rendering
Given a stored street address and masking mode is "City/State Only" When address fields render across UI, CSV, PDF, and e-sign preview Then only City and State appear, street line(s) and unit/apartment are omitted, and ZIP is omitted And downstream document assembly may use the full address internally but all outputs adhere to the City/State-only mask Given a user without "View Full Address" permission When attempting to reveal the address Then the street and unit remain hidden and any copy/export action yields only City and State
Email Local-Part Masking Consistency
Given a stored email address in the form local@domain and email masking mode is "Mask Local Part" When the email renders across UI, CSV, PDF, and e-sign preview Then the value displays as F***L@domain where F and L are the first and last characters of the local part and the middle characters are replaced by asterisks matching the count of omitted characters And clicking to copy or export preserves the masked pattern; hyperlinks use mailto with the full email only at send time without exposing it in visible text or logs Given a user searches by full email value When results are listed Then the matched record is returned but the email remains masked in the results and detail views
Global Formatting Consistency and Exposure Validation
Given field-level masking configurations are set for SSN, PAN, DOB, Address, and Email When any screen, CSV export, PDF generation, or e-sign preview renders these fields Then each field conforms to its configured partial reveal mode and mask characters, with identical formatting across all surfaces and locales Given logging, analytics, and error messages are generated during intake and document assembly When they include references to masked fields Then they never include full sensitive values and include at most the permitted unmasked fragments per mode Given any process attempts to output a sensitive field exceeding its permitted unmasked length When validation runs Then the system blocks the output, replaces it with a redaction token, and surfaces a non-sensitive validation error to the user
End-to-End Masked Data Propagation (UI, Docs, E-sign, Integrations)
"As a document drafter, I want masked placeholders to render in assembled documents by default so that drafts are safe to share internally and with clients."
Description

Ensure masked representations are the default throughout the lifecycle: form rendering, workflow steps, conflict screening, document assembly templates, e-sign packets, audit exports, and third-party integrations. Provide template engine helpers to choose masked vs. unmasked tokens based on permission context, and include masking-state flags in API payloads. Use salted hashing or tokenization for equality/duplicate checks and conflict screening to avoid transmitting full PII. Require explicit elevated scopes for any unmasked API response. The outcome guarantees that redaction persists across channels and automations without breaking critical operations.

Acceptance Criteria
Default PII Masking in Intake UI and Workflow Steps
Given a staff user without unmask permissions When they view or edit an intake form containing SSN, DOB, address, and payment fields across any workflow step Then SSN displays as ***-**-#### (last 4 only), DOB as **/**/YYYY, address as [City, State, ZIP] only, and payment as **** **** **** #### And masked representations persist when navigating between steps, saving drafts, re-opening, and printing the screen And copying these fields to clipboard copies the masked value And the HTML source, Redux/local storage, and network requests for the page contain only masked values for these fields
Permissioned Reveal with Time-Bound Unmask and Audit Trail
Given a staff user with the PII.Unmask permission and an MFA-authenticated session within the last 15 minutes When they click Reveal on a masked SSN field and provide a justification Then the full SSN is displayed for a maximum of 5 minutes or until page navigation, after which it automatically re-masks And an audit record is written capturing user, record ID, field name, justification, timestamp, and duration of reveal And users without PII.Unmask or with stale MFA are blocked from reveal with a 403 UI error and the value remains masked And exported screenshots/print-to-PDF of the UI during masked state never display unmasked values
Template Helpers and Masked Output in Document Assembly and E‑Sign
Given a document template that references PII fields When assembled without an explicit unmask scope Then all PII tokens render using masked helpers by default (e.g., {{client.ssn.masked}}, {{client.dob.masked}}) And using {{unmask client.ssn}} renders the masked value unless the assembly job is created with scope=pii.unmask and a justification string And e‑sign packets and internal previews show masked values to staff, while signers (data subjects) see their own unmasked values only if envelope policy reveal_to_signer=true And envelope metadata, email subjects/bodies, and audit certificate never include full PII
Tokenized Conflict Screening and Duplicate Detection Without Raw PII
Given an intake submission containing SSN and DOB When conflict screening runs Then SSN and DOB are transformed using salted hashing or tokenization before matching And exact-match duplicates are detected with 100% recall on a test set of ≥1,000 known duplicate pairs And no raw SSN or full DOB leaves the application boundary or appears in logs during the process And the screening result payload contains only tokens and masking-state flags
API and Webhook Enforcement of Masking-State and Scopes
Given an API client with standard scopes When they call GET /clients/{id} Then PII fields return masked_value plus masking_state="masked" and never include raw values And requests for unmasked values require scope pii.unmask and header X-Unmask-Justification; otherwise return 403 And all outbound webhooks and third-party integrations receive masked values by default with masking_state flags present And API schemas and OpenAPI docs reflect masked/unmasked variants and scope requirements
Audit Exports and Application Telemetry Preserve Redaction
Given an admin generates an audit export When no unmask override is provided Then the export contains masked values for all PII and is labeled as masked in filename and metadata And requesting an unmasked export requires admin role, pii.unmask scope, fresh MFA, and a justification captured in the audit log And application logs, analytics events, and error traces redact PII consistently, verified by automated scanners finding zero occurrences of raw SSN/DOB/address lines in generated telemetry during integration tests
Reveal Event Auditing and Alerts
"As a compliance officer, I want a detailed audit trail of all PII reveal events so that I can monitor and investigate potential misuse."
Description

Capture immutable logs for every reveal attempt and success including timestamp, user, role, IP/agent, field name, record ID, reason provided, source (UI/API), viewing duration, and approval references where applicable. Provide audit views, scoped exports, retention policies, and anomaly detection (e.g., excessive reveals per user or after-hours access). Send real-time alerts to admins via email/Slack for high-risk fields and policy violations. The outcome supports compliance investigations and proactive risk mitigation.

Acceptance Criteria
Comprehensive Reveal Event Logging and Immutability
Given a masked field reveal is attempted via UI or API, When the request is received, Then a log entry is created with timestamp (UTC ISO-8601), tenantId, userId, role, ipAddress, userAgent, recordId, fieldName, riskLevel, source (UI|API), outcome (attempt|success|denied), reason (nullable), approvalRef (nullable), and viewingSessionId (nullable) Given a failed reveal (e.g., insufficient role, invalid token, missing reason), When the failure occurs, Then a log entry is recorded with outcome=denied and errorCode set Given any existing log entry, When a user attempts to modify or delete it, Then the system prevents the change and records a separate append-only administrative event noting the attempted modification Given an API reveal, When the clientId/appKey is missing or invalid, Then the request is rejected and an attempt log is recorded with source=API and outcome=denied
Reason and Approval Enforcement for Full Reveals
Given org policy RequireReasonForReveal is enabled, When any user attempts a reveal, Then the UI/API requires a non-empty reason with a minimum length of 10 characters and the attempt is blocked until provided Given field riskLevel=High and user role is not in {Partner, Admin}, When a full reveal (not partial/last-4) is requested, Then supervisor approval is required and the reveal is denied until approval is granted and logged with policy=ApprovalRequired Given an approval is granted by a Partner or Admin, When the requester retries within 24 hours, Then the reveal succeeds and the log entry includes approvalRef linking approvalId and approverId Given an approval expires (older than 24 hours) or is revoked, When the user retries, Then the reveal is denied and a log is stored with outcome=denied and policy=ApprovalExpiredOrRevoked
Viewing Duration Capture and Auto-Remask
Given a successful reveal in the UI, When the value is displayed, Then a viewing session starts and startTimestamp is recorded; after 60 seconds of inactivity or on navigation away the value is remasked, endTimestamp is recorded, and viewingDurationSeconds=end-start is stored Given multiple reveals of the same field within one session, When each reveal occurs, Then each viewing session is separately logged with its own viewingSessionId and duration Given a reveal via API, When clear-text data is delivered, Then viewingDurationSeconds is null and deliveryTimestamp is recorded Given a browser tab is closed or the session ends unexpectedly, When the heartbeat stops, Then the viewing session ends within 10 seconds and duration is recorded using the last heartbeat time
Audit View Filtering and Scoped Export
Given a user with permission Audit.View, When they open the audit view, Then they can filter by date range, userId, role, outcome, fieldName, recordId, riskLevel, source, ipAddress, and reason contains Given filters are applied, When Export CSV is requested, Then a CSV is generated containing only filtered rows with columns: timestampUTC, tenantId, userId, role, ipAddress, userAgent, recordId, fieldName, riskLevel, source, outcome, reason, approvalRef, viewingDurationSeconds, incidentId, and the file is UTC-normalized Given a multi-tenant environment, When an auditor exports, Then only records for their tenant are included and cross-tenant data is excluded Given an export exceeding 100,000 rows, When the export is initiated, Then the system paginates and provides a download link for each part and logs an ExportCreated event referencing the filter set
Retention Policy and Legal Hold
Given retentionDays=365 and no legal hold, When a log record exceeds 365 days, Then the record is purged or redacted per policy and a purge receipt with timestamp, tenantId, count, and checksum is appended to the retention audit log Given a legal hold is active for a matter or tenant, When the retention job runs, Then matching records are not purged until the hold is released and the skip is logged Given retention configuration is changed, When a user saves the change, Then the system logs who, when, oldValue, newValue, and reason, and applies the new value to subsequent purge runs Given a purge run fails mid-execution, When the job resumes, Then the process is idempotent and does not re-purge already purged records, and a failure event with error details is recorded
Anomaly Detection and Incident Creation
Given thresholds HighVolume=X=10 reveals in Y=5 minutes per user and AfterHours=19:00–07:00 tenant local time, When a threshold is exceeded, Then an anomaly is detected within 60 seconds, an Incident record is created linking all contributing logIds, and anomalyType is set (HighVolume|AfterHours) Given an IP geolocation change >500 km within 30 minutes for the same user, When the next reveal occurs, Then an anomaly is raised with anomalyType=GeoVelocity and linked to both source and destination IPs Given repeated triggers of the same anomaly type, When they occur within 30 minutes, Then incidents are deduplicated to one open incident per user per type and subsequent logs are appended to the incident Given an incident lifecycle, When status changes (Open→Acknowledged→Resolved), Then each transition is audited with timestamp, actor, and reason
Real-Time High-Risk Alerts via Email and Slack
Given a reveal of a High-risk field (SSN, full DOB, payment PAN) or a policy violation (denied reveal, after-hours), When the event is logged, Then all admins with Alert.Recipient enabled receive an email and Slack notification within 60 seconds Given an alert is sent, When delivered, Then the payload includes tenantId, userId, role, fieldName, recordId, source, outcome, reason, ipAddress, timestampUTC, incidentId (if any), and a deep link to the audit view Given a channel delivery failure, When it occurs, Then the system retries with exponential backoff for up to 15 minutes and records AlertDeliveryFailed events; unresolved failures appear in an Alert Health dashboard Given an admin updates alert preferences or quiet hours, When saved, Then changes take effect within 5 minutes and are audited; policy-violation alerts bypass quiet hours
Emergency Unmask Workflow with Justification and Approval
"As an attorney, I want an emergency unmask option with required justification so that I can meet court deadlines when the approver is unavailable."
Description

Introduce a break-glass pathway that temporarily unmask specific fields/records when urgently needed. Require structured justification, optional manager approval routing, and automatic re-masking after a configurable time window. Notify stakeholders on use, and log all actions. Support offline codes for courthouse scenarios with later synchronization. The outcome provides a safe, controlled exception path for time-sensitive legal tasks.

Acceptance Criteria
Justification Capture on Emergency Unmask Request
Given a user with Break-Glass Request permission views a masked field on a client intake record When the user clicks Unmask and selects specific field(s) Then the system presents a modal requiring: justification (min 15 characters), urgency category, related Matter/Lead ID, requested duration (<= org maximum), and policy acknowledgment And the Submit button remains disabled until all validations pass And submitting creates an immutable audit entry capturing user ID, record ID, field names, justification, requested duration, timestamp, and reason category And the workflow proceeds to approval or immediate unmask per policy
Manager Approval Routing for High-Risk Fields
Given org policy requires approval for the selected field category (e.g., SSN, full DOB, payment data) When a valid unmask request is submitted Then the request is routed to the designated approver group with SLA timer and in-app/email notification And approvers can Approve or Deny with mandatory comment; decision, approver ID, and timestamp are logged And if no action is taken before SLA expiry, the request auto-denies or escalates per org configuration And upon approval the targeted fields become unmasked for the requester; upon denial they remain masked and the requester is notified
Auto Re-Mask After Configurable Time Window
Given an approved unmask with duration D is active When D expires, the user signs out, or the session is inactive for the configured timeout Then the system re-masks the fields, revokes any temporary access tokens, and logs the expiry And the UI displays a countdown banner during the active window and a re-masked state after expiry And any extension request requires a new justification and (if applicable) approval And document assembly/export reverts to masked output after expiry
Scope-Limited, Session-Bound Unmasking
Given an unmask is approved for specific fields on a specific record When the requester views the record during the active window Then only the specified fields are shown unmasked to the requester in their current session And all other users and API consumers continue to receive masked values And bulk export and list views remain masked unless explicitly included in the approved scope And copy/download of full values is blocked outside the approved scope and time window
Stakeholder Notifications Without Data Leakage
Given an unmask request is submitted, approved, denied, or expired When any of these events occur Then the system notifies the requester, matter owner, and compliance group via in-app and email channels And notifications include requester, record ID, field names, justification summary, timestamps, and links; no full sensitive values are included And queued notifications for offline actions are delivered within 1 minute of synchronization
Offline One-Time Code Unmask Flow with Sync
Given the user is offline and possesses a valid unused one-time emergency code bound to their account and org When the user enters the code, selects fields, and provides justification Then the device grants local unmask for those fields for the code’s maximum duration and stores an encrypted local audit record And invalid, expired, or already-used codes are rejected with a clear error And upon next online sync, the audit is uploaded, stakeholders are notified, and the event is queued for post-hoc review per policy
Tamper-Evident Audit Trail and Reporting
Given break-glass activity has occurred within a date range When an authorized user runs the Break-Glass Audit report Then each event shows actor, record, field names, justification, approval outcome, timestamps, duration, device/IP, and (if used) offline code ID And audit entries are append-only with verifiable checksums; integrity verification returns OK And reports can be filtered, exported (with values redacted), and retained per org policy
Admin Policy Console and Templates
"As an office admin, I want a policy console with templates so that I can deploy consistent masking without writing code."
Description

Deliver an admin UI to configure mask rules, partial reveal formats, role permissions, approval workflows, alert thresholds, and retention periods. Provide jurisdiction-aware templates for common family-law data elements and filings, a sandbox preview to test policies on sample records, versioning with audit-friendly change logs, rollback, and import/export across tenants. The outcome empowers firms to deploy consistent masking policies quickly without engineering support.

Acceptance Criteria
Mask Rule Creation and Sandbox Preview (Partial Reveal)
Given I am an Org Admin with access to the Admin Policy Console And a sample record exists with SSN "123-45-6789" and DOB "2001-02-03" When I create a mask rule for field "SSN" with pattern "XXX-XX-{last4}" And I create a mask rule for field "DOB" with pattern "YYYY-**-**" And I save the policy as Draft Then the Sandbox Preview displays SSN as "XXX-XX-6789" and DOB as "2001-**-**" And no API or UI endpoint in preview returns the unmasked values When I publish the policy as version "1.0" Then the same masking applies in Intake forms and Document Assembly previews within 60 seconds of publish And the policy status shows "Published v1.0" with timestamp and publisher identity
Role-Based Visibility and Time-Bound Unmask Approval
Given roles "Intake Staff" and "Partner" exist And the policy sets "SSN" visibility: masked for "Intake Staff" with unmask by approval; full visibility for "Partner" And the unmask approval workflow requires 1 approver from role "Partner" and an unmask window of 10 minutes When an Intake Staff user views a record with SSN "123-45-6789" Then they see "XXX-XX-6789" and no full value is present in the DOM or network responses When the user requests unmask with reason "Verify identity" Then a Pending Approval appears for Partners and a notification is sent When a Partner approves the request Then the Intake Staff user sees the full SSN for at most 10 minutes and the value re-masks automatically afterward And an audit log records requester, approver, reason, timestamps, duration, and field accessed When a Partner rejects the request Then the SSN remains masked and the request is logged with the rejection reason
Jurisdiction-Aware Policy Templates for Family-Law
Given jurisdiction "California" and filing type "Dissolution of Marriage" are selected in the Admin Policy Console When I load the jurisdiction-aware template Then default mask rules appear for fields: SSN (XXX-XX-{last4}), DOB (YYYY-**-**), Home Address (city/state only), Payment Card (**** **** **** {last4}) And fields marked "Jurisdiction-Locked" cannot be edited without override and justification When I customize an editable rule (e.g., set Address detail to "city only") Then the console validates the schema, highlights impacted forms/documents, and saves the override to Draft And the template records jurisdiction, version, and effective date metadata
Versioning, Change Log, and Rollback
Given a Published policy v1.0 exists When I modify the DOB mask from "YYYY-**-**" to "YYYY-MM-**" and add note "Court requires month" And I submit for approval and publish Then a new version v1.1 is created with a diff showing field-level changes (old vs new), author, approver, timestamps, and release notes And the audit log includes a unique change ID and a hash of the exported policy When I perform a rollback to v1.0 Then Intake and Document Assembly apply v1.0 rules within 60 seconds And v1.2 is recorded as "Rollback to v1.0" with appropriate changelog entries
Alert Thresholds for Unmask Events
Given an alert threshold of "3 unmask events per user per 24 hours" for fields SSN and Payment Card is configured When a user performs a 4th unmask event within 24 hours Then an alert is generated in-app and via email to the Compliance role within 1 minute And the user is soft-limited from further unmasking until a Compliance override or the window resets And the alert and enforcement are recorded in the audit log with event counts and timestamps When the threshold is changed to 5 and saved Then the new threshold applies to subsequent events and is reflected in policy metadata
Retention Policy and Automated Purge with Hold Respect
Given a retention policy "Purge SSN and Payment Card after 90 days from matter close" is configured And a nightly purge job is enabled at 02:00 local time When a matter closes and 90 days elapse without a litigation hold Then the purge job irreversibly redacts SSN and Payment Card values (preserving last-4 only) and writes a purge receipt per record And no backups retained beyond policy allow restoration of full values When a litigation hold is applied before the 90th day Then the purge is skipped for affected records and the hold reason is recorded
Cross-Tenant Policy Export/Import with Validation
Given a Published policy v1.1 exists in Tenant A When I export the policy Then I receive a signed JSON package containing policy definition, templates, jurisdiction metadata, and a SHA-256 checksum When I import the package into Tenant B Then the system validates the signature and checksum, maps roles to Tenant B equivalents, flags missing dependencies, and creates a Draft policy And no rules become active until explicitly published in Tenant B And all IDs are namespaced or remapped to avoid collisions and a migration report is stored

Stage Gates

Progressive access rules tied to intake stages (qualify, conflict check, engagement, assembly). After‑Hours staff see only contact and qualification fields; attorneys unlock financials post‑engagement. Keeps momentum high and leakage low by revealing the right data at the right time.

Requirements

Stage Policy Configuration Console
"As a firm admin, I want to configure which fields are visible or editable by role at each intake stage so that staff see only what they need and sensitive data remains protected."
Description

A centralized administration interface within CaseSpark to define, version, and deploy stage-gate policies across the intake lifecycle (qualify, conflict check, engagement, assembly). Admins configure which roles can view, edit, or are masked from specific field groups at each stage, with conditional rules such as time-of-day (After-Hours), location, or device. Includes policy versioning, draft/publish workflows, preview-as-role, and import/export for templates by practice area and jurisdiction. Policies apply consistently to both UI and API, ensuring least-privilege access, faster workflows, and reduced data leakage.

Acceptance Criteria
Configure role-based field group permissions per stage
Given I am an Admin in the Stage Policy Configuration Console And a draft policy exists for Practice Area "Family Law" and Jurisdiction "CA" And the field groups "Contact", "Qualification", "Financials", and "Sensitive" exist When I set at stage "Qualify": role "After-Hours Staff" = view Contact, view Qualification, no access Financials, no access Sensitive And I set at stage "Engagement": role "Attorney" = edit Financials, view Sensitive And I save the draft Then the draft persists with a unique version id and last-modified timestamp And on publish, a user with role "After-Hours Staff" at stage "Qualify" can see Contact and Qualification, cannot see or search Financials and Sensitive And attempting to open or search Financials or Sensitive returns a 403 POLICY_DENIED with policyVersion in the API and an inline message "Access restricted by stage policy" in the UI And a user with role "Attorney" at stage "Engagement" can create and update Financials and cannot update Sensitive
Time-of-day After-Hours restriction override
Given business hours 08:00–18:00 America/Los_Angeles are defined in policy And a rule maps base role "Intake Specialist" to permissions of role "After-Hours Staff" outside business hours When the current time is 19:30 America/Los_Angeles and a user with base role "Intake Specialist" opens an intake in stage "Qualify" Then only Contact and Qualification field groups are visible in the UI And Financials and Sensitive are hidden and non-queryable And calling GET /intakes/{id}/fields?group=Financials returns 403 with code "POLICY_DENIED" and includes policyVersion When the current time is 09:00 America/Los_Angeles Then the same user at stage "Qualify" has permissions per base role "Intake Specialist" without the after-hours override
Publish policy version with effective date and staged rollout
Given a draft policy version v1.3 exists with change summary When I schedule publish for 2025-09-15T00:00 America/Los_Angeles Then the version status is "Scheduled" and effectiveAt is set to 2025-09-15T00:00-07:00 When the wall clock passes effectiveAt Then v1.3 status becomes "Published" and the version is immutable And v1.2 remains retained and viewable in history And new intakes created after effectiveAt use v1.3 automatically And in-progress intakes continue under their current version until their next stage transition, at which point v1.3 applies And an audit entry records publisher, timestamp, and diff summary
Preview-as-role/stage with masking verification
Given a published policy masks Financials and Sensitive for role "After-Hours Staff" at stage "Conflict Check" When I open Preview and select Role = "After-Hours Staff", Stage = "Conflict Check", Device = "Mobile", Time = 21:00 America/Los_Angeles Then the preview renders placeholders (•••) for all masked fields and disables their controls And the preview JSON shows masked=true for those fields and includes policyVersion id When I switch Role to "Attorney" and Stage to "Engagement" Then Financials fields appear editable in the preview and masked=false
Policy import/export with jurisdiction validation
Given a published policy template exists for Practice Area "Family Law" and Jurisdiction "CA" When I export the template Then a JSON file is downloaded containing schemaVersion, policyVersion, checksum, practiceArea, jurisdiction, and role mappings When I modify the file to set jurisdiction="NV" and import it as a draft Then the system validates the schema and prompts to map any unknown roles And on successful mapping, a draft v0.1 for jurisdiction "NV" is created with a validation report and no errors When I tamper with the file checksum and attempt import Then the import is rejected with error code "INVALID_CHECKSUM" and no draft is created
Consistent enforcement across UI and API
Given a published policy denies access to the Financials group for role "After-Hours Staff" at stage "Qualify" When a user with role "After-Hours Staff" opens the Qualify screen Then the UI does not render the Financials group and displays a non-blocking banner "Access restricted by stage policy" When the same user calls GET /intakes/{id}/fields?group=Financials Then the API responds 403 with code "POLICY_DENIED", correlationId, and policyVersion When a user with role "Attorney" at stage "Engagement" calls the same endpoint Then the API responds 200 with Financials data and the UI shows Financials editable
Location/device conditional masking (geo-fence + mobile)
Given a rule: if Device = Mobile and user geolocation is outside the office geofence (radius 100m around 123 Main St, CA), then mask the "Sensitive Documents" group at all stages When a user on a Mobile device outside the geofence opens the Engagement stage Then the "Sensitive Documents" list is not visible in the UI And GET /intakes/{id}/documents?group=Sensitive returns 403 with code "POLICY_DENIED" and reason="GeoFence" When the same user moves inside the geofence or switches to a Desktop device Then "Sensitive Documents" visibility follows the base role/stage policy and API requests return according to those permissions
Field-Level Access Controls Engine
"As a developer integrating CaseSpark, I want server-enforced field-level permissions so that data cannot be accessed or modified by circumventing the UI."
Description

A runtime enforcement service that evaluates stage-gate policies per request to control field-level visibility, editability, and masking across UI and API. Implements server-side authorization to prevent bypassing the UI, returning consistent error codes and redaction for unauthorized reads/writes. Supports optimistic caching with TTL, high-throughput evaluation, and deterministic outcomes for real-time intake. Enforces audit-friendly decisions (who/what/why) and maintains parity across web, mobile, and integrations.

Acceptance Criteria
After-Hours Read Redaction at Qualify Stage
Given a user with role "AfterHoursStaff" and intake stage "Qualify" When requesting a client record via Web, Mobile, or API Then only fields tagged Contact or Qualification are returned as visible/editable And all other fields are returned with value null and mask "REDACTED" And the API response status is 200 and includes "redactedFields" listing masked fields And the audit log contains subjectId, resourceId, fieldsMasked, policyId, and reason "stage-gate"
Unauthorized Write Blocking and Error Codes
Given a user lacks write permission for any field in the submitted payload by current policy When attempting to create or update the record via API or UI Then the write is rejected atomically with HTTP 403 and error.code "E_FIELD_FORBIDDEN" And response includes "blockedFields" with per-field reason codes And no changes are persisted to the resource And an audit entry is recorded with outcome "deny" and the same decisionId as returned in the response
Deterministic Decisions Across Channels
Given identical subject (user, role, tenant), resource, fields, stage, and request timestamp (±1s) When the decision is evaluated via Web, Mobile, and Public API Then outcomes (allow/deny/mask) and reason codes are identical across channels And decisionId and policyVersion values are identical across channels And direct API calls from the same subject receive the same decision as the UI (no UI-bypass discrepancy)
Optimistic Cache with TTL and Invalidation
Given a default policy TTL of 60s configurable per tenant (range 5–300s) When a policy is updated and published Then cached policy entries are invalidated globally within 5s And evaluations served from cache have P95 latency ≤ 10ms And stale decisions never exceed the configured TTL And a cache-miss evaluation completes with P95 latency ≤ 50ms
High-Throughput Evaluation SLA
Given a steady load of 2,000 RPS per engine instance with 50% cache hit rate When evaluating access decisions Then overall error rate is < 0.01% over any rolling 15-minute window And end-to-end P95 latency ≤ 20ms and P99 ≤ 60ms per decision And the engine scales linearly from 1 to 5 instances to maintain these SLOs
Audit Decision Completeness and Integrity
Given any access decision (allow/deny/mask) When the decision is produced Then an immutable audit record is written within 1s including subjectId, role, tenantId, resourceId, fieldIds, action, stage, outcome, policyId, policyVersion, reasonCodes, decisionId, channel, requestId, and timestamp And retrieving the audit record by decisionId returns within 200ms And sensitive field values are not persisted in audit when outcome is mask or deny
Stage Transition Unlocks Financials Post-Engagement
Given a user with role "Attorney" and a matter at stage "Engagement" due to a signed engagement event When reading or editing fields tagged Financials Then the fields are visible and editable And at stages "Qualify" and "Conflict Check" the same fields are masked and writes are forbidden with HTTP 403 and error.code "E_FIELD_FORBIDDEN" And reverting the matter to a prior stage immediately revokes access to Financials And audit entries reflect the stage used in each decision
Stage Transition Validator
"As an intake specialist, I want clear rules that prevent moving to engagement until conflict checks and required fields are complete so that I don’t accidentally proceed with a conflicted or incomplete matter."
Description

Deterministic rules and validations governing movement between intake stages, including prerequisites (e.g., conflict check result = pass, signed engagement = true), data completeness checks, and hard/soft blocks with actionable reasons. Supports backtracking with controlled side effects (e.g., re-locking financials), prevents illegal or circular states, and emits webhooks/notifications on transitions. Provides inline guidance to resolve blockers to keep intake momentum high.

Acceptance Criteria
Qualify -> Conflict Check: Required data and soft-block behavior
Given a matter in stage=Qualify and all configured required qualification fields are complete When a user attempts transition to Conflict Check Then the transition succeeds, the stage becomes Conflict Check, and an audit entry records actor, timestamp, fromStage, toStage Given a matter in stage=Qualify with at least one required qualification field missing When a user attempts transition to Conflict Check Then the transition is hard-blocked with code=REQUIRED_FIELDS_MISSING and a list of missingFieldKeys is returned along with inline guidance links for each field Given a matter in stage=Qualify with optional fields missing but all required fields complete When a user attempts transition to Conflict Check Then a soft block lists optionalFieldKeys and offers a Continue action; users with permission can proceed, and a bypass note with reason is recorded in the audit log Given the transition is attempted via API and is blocked When the validator responds Then HTTP 409 is returned with machine-readable reasonCodes; if successful, HTTP 200 is returned with newStage=Conflict Check and a unique transitionId
Conflict Check -> Engagement: Conflict outcomes and financials unlock
Given stage=Conflict Check and conflictCheck.result=pass When a user attempts transition to Engagement Then the transition succeeds, stage=Engagement, attorney roles gain read/write access to financial fields, and non-attorney roles remain restricted Given stage=Conflict Check and conflictCheck.result=fail When a user attempts transition to Engagement Then the transition is hard-blocked with code=CONFLICT_FAILED and guidance includes actions to decline or seek waiver; financial fields remain locked for all non-attorney roles Given stage=Conflict Check and conflictCheck.result=pending When a user attempts transition to Engagement Then the transition is soft-blocked with code=CONFLICT_PENDING, a CTA to Run Conflict is shown, and only Attorney role may override with overrideReason required and captured in audit Given multiple conflict screenings exist When evaluating pass/fail for transition Then the most recent finalized screening determines the outcome
Engagement -> Assembly: Signed engagement prerequisite
Given stage=Engagement and signedEngagement=true When a user attempts transition to Assembly Then the transition succeeds, stage=Assembly, an audit entry is recorded, and webhook stage.transition.succeeded is emitted Given stage=Engagement and signedEngagement=false When a user attempts transition to Assembly Then the transition is hard-blocked with code=ENGAGEMENT_NOT_SIGNED and guidance includes a CTA to send or resend the e-sign packet Given signedEngagement=true and retainerPaymentRequired=true and retainerPaymentStatus=pending When a user attempts transition to Assembly Then the transition is soft-blocked with code=RETAINER_PENDING, a CTA to Record Payment is shown, and Attorney role may override with overrideReason and amountDeferred captured
Backtrack Engagement -> Qualify: Controlled side effects and relocking
Given stage=Engagement and a user with Backtrack permission provides a reason When backtracking to Qualify is initiated Then the stage updates to Qualify, financial fields are re-locked for all non-attorney roles, and an audit entry records actor, reason, fromStage, toStage, and sideEffects Given a backtrack completes When webhooks are enabled Then event stage.transition.reverted is emitted with matterId, fromStage, toStage, originalTransitionId (if present), occurredAt, and signature Given a backtrack is in progress When another transition request is received for the same matter Then it is rejected with code=TRANSITION_IN_PROGRESS and retryAfter is provided Given a user without Backtrack permission or missing reason attempts backtrack When the request is validated Then it is blocked with code=UNAUTHORIZED or code=REASON_REQUIRED
Prevent illegal, skipped, circular, or duplicate transitions
Given any matter When a transition attempts to skip a mandatory stage (e.g., Qualify -> Engagement without Conflict Check) Then it is hard-blocked with code=ILLEGAL_TRANSITION and allowedPaths are returned Given a matter already in target stage When a duplicate transition to the same stage is requested Then the validator responds with success=false, code=NO_OP, and state remains unchanged (idempotent) Given two concurrent transition requests for the same matter When processed by the validator Then exactly one succeeds and the other receives code=TRANSITION_CONFLICT with retryAfter seconds Given a request to backtrack more stages than policy allows When validated Then it is blocked with code=BACKTRACK_LIMIT and maxBacktrackSteps is returned Given a transition configuration introduces a cycle When configuration is validated Then it is rejected with code=CONFIG_CYCLE_DETECTED and the offending path is reported
Webhooks and notifications on transition events
Given any successful transition When it completes Then a webhook stage.transition.succeeded is emitted exactly once per transitionId with payload {matterId, fromStage, toStage, transitionId, actorRole, occurredAt} signed with HMAC and retried with exponential backoff up to 6 times on non-2xx Given any blocked transition When the block is determined Then a webhook stage.transition.blocked is emitted with {matterId, fromStage, attemptedToStage, reasonCodes, missingFieldKeys?} Given user notification preferences include in-app and email When a transition succeeds or is blocked Then an in-app notification and email are sent within 60 seconds and deduplicated per transitionId Given a webhook endpoint returns 2xx When delivery completes Then the attempt is marked delivered; if it never returns 2xx after max retries, it is marked failed with lastError stored and visible in admin logs
After-Hours Restricted Mode
"As an answering service agent, I want a simplified view with only contact and qualification information after business hours so that I can triage callers without exposing confidential financial data."
Description

A schedule-aware access mode that automatically limits After-Hours staff to contact and qualification fields during defined off-hours. Hides or masks financial, sensitive PII, documents, and notes; disables export/print/download; and enforces read-only where appropriate. Can be toggled per firm, per queue, or per user with timezone-awareness, visual banners, and session time limits. All access is logged for compliance and quality assurance.

Acceptance Criteria
Auto-Activation by Off-Hours Schedule (Timezone-Aware)
Given a firm off-hours schedule of 18:00–08:00 set to America/New_York And the user's role is After-Hours Staff And the user signs in at 19:30 America/New_York time When the session is established Then After-Hours Restricted Mode is activated for that session And a request made after 08:00 America/New_York automatically deactivates the mode within 60 seconds or on the next request And sign-ins occurring at 10:00 America/New_York do not activate the mode And if a user-specific override timezone is set, the schedule is evaluated against that timezone instead of the firm timezone
Field Visibility Restriction to Contact and Qualification
Given After-Hours Restricted Mode is active for an After-Hours Staff user When viewing an intake record Then only fields in the Contact and Qualification categories are visible And fields in Financial, Sensitive PII (e.g., SSN, DOB, DL), Documents, and Notes categories are not rendered And where UI requires field presence, values are masked with "Redacted" and no underlying value is present in the DOM or API response And full-text search and autosuggest do not return terms originating from hidden/masked fields
Read-Only Enforcement Outside Allowed Categories
Given After-Hours Restricted Mode is active When the user attempts to edit, create, or delete any data outside the Contact and Qualification categories (including uploading documents and modifying notes) Then the action controls are hidden or disabled in the UI And any direct API attempt returns HTTP 403 with reason "restricted_mode" And the attempt is blocked without partial writes And the blocked attempt is audit-logged with user, resource, action, outcome=blocked, and reason
Export/Print/Download Disabled (UI and API)
Given After-Hours Restricted Mode is active When the user attempts to use Export CSV/PDF, Print, or Download actions from any page Then all export/print/download UI controls are not rendered or are disabled with tooltip "Disabled in After-Hours Restricted Mode" And server endpoints for export/print/download return HTTP 403 with reason "restricted_mode" And no file payload is generated or streamed And the blocked attempts are audit-logged with action and outcome=blocked
Scoped Toggles with Override Precedence (Firm, Queue, User)
Given firm-level After-Hours Restricted Mode is enabled with an off-hours schedule And a specific intake queue has the mode disabled (override) And a specific user within that queue has the mode enabled (override) When that user signs in during off-hours and accesses that queue Then the user-level override takes precedence and the mode is active When another user in the same queue (without a user-level override) signs in during off-hours Then the queue-level override applies and the mode is not active And when accessing a different queue without an override, the firm-level setting applies
Visual Banner and Session Time Limit Enforcement
Given After-Hours Restricted Mode is active When the user navigates any page Then a persistent banner appears stating "After-Hours Restricted Mode", the reason (Schedule/Override), and the local end time of the restriction based on the evaluated timezone And the banner is accessible (meets WCAG AA: role=alert, contrast ≥ 4.5:1, keyboard focusable link to details) And when the configured inactivity timeout (e.g., 30 minutes) is reached, the session is terminated and the user is redirected to sign-in with a message about restricted-mode timeout And a warning dialog appears 5 minutes before timeout with a countdown, and user activity resets the inactivity timer And a configured absolute session cap (e.g., 2 hours) logs the user out even with activity And all timeouts are audit-logged
Comprehensive Access Logging for Compliance
Given After-Hours Restricted Mode is active When the user views a record, edits allowed fields, or attempts a blocked action (e.g., export) Then an audit log entry is written within 5 seconds containing: timestamp (UTC), evaluated timezone, userId, role, scope (firm/queue/user), action, resource, outcome (allowed/blocked), reason (restricted_mode), ip, userAgent, and sessionId And no sensitive field values (e.g., SSN, full DOB, financial amounts) are stored in the log payload And authorized auditors can filter logs by user, action, outcome, and time range and export them outside of restricted mode And log integrity is protected with append-only storage and checksum to detect tampering
Engagement-Triggered Financial Unlock
"As an attorney, I want financial fields to unlock automatically once the engagement letter is signed so that I can discuss fees and collect retainers without delay."
Description

Automated unlocking of financial fields and payment workflows for attorney roles upon verified engagement execution via integrated e-sign providers. Listens to signed/voided events, validates signer identities, and updates access controls accordingly. Supports multi-signer engagements, immediate notifications, and re-locking if the engagement is revoked or expires. Configurable exceptions and manual override with audit capture ensure continuity when edge cases arise.

Acceptance Criteria
Verified Engagement Unlock for Attorney Roles
Given an engagement envelope is associated to a matter and all signer identities are verified And the current user has an Attorney role assigned to the matter When the e-sign provider posts a completed event for that envelope Then the system unlocks Financials.View and Financials.Edit for Attorney-assigned users on that matter within 5 seconds of event receipt And enables payment workflows (retainer request, payment plan setup, invoice issuance) And non-attorney roles remain restricted unless allowed by configured exceptions And an audit record is created with event type, envelope ID, provider, timestamp, matter ID, and actor "system"
Multi-Signer Completion Gate
Given a matter requires N required signers for engagement completion And fewer than N have completed signing When any partial completion event is received Then financial fields remain locked and payment workflows disabled When all N required signers have completed and any required attorney counter-signature is captured Then the unlock process is triggered once and only once And the audit record lists each signer, their verification status, and timestamps
Void/Revocation/Expiry Re-lock
Given financial fields are unlocked due to a completed engagement When the e-sign provider sends a voided, revoked, or expired event for the envelope, or the matter is marked "engagement revoked" Then the system re-locks financial fields and disables payment workflows within 5 seconds And notifies assigned attorneys of the re-lock with reason code And any in-progress payment session is invalidated with a user-facing error message And an audit entry records previous state, reason code, envelope ID, and timestamp
Identity Validation Gate
Given identity verification is required for all required signers When any required signer fails or skips identity verification Then financial fields do not unlock and a "verification_failed" reason is recorded When all required signers pass identity verification Then the unlock may proceed subject to other gates And the audit record includes verification method (e.g., SMS OTP, KBA), provider references, and check IDs And if the provider cannot supply verification status, a manual override is required to unlock
Immediate Notification Dispatch
Given an unlock or re-lock event occurs for a matter When the state change is committed Then in-app notifications are delivered to assigned attorneys within 10 seconds containing client name, matter ID, envelope ID, event type, and initiator And email notifications are sent respecting user notification preferences, with up to 3 retry attempts on failure And notification send results (success/failure) are logged and visible to admins
Access Control Propagation and Session Behavior
Given access control changes are applied by the unlock/re-lock When authorized users access the matter Then permissions update across: Matter Financials tab, Retainer Requests, Payment Plans, Invoices, and related API endpoints And active sessions reflect new permissions on the next request/refresh without requiring logout And After-Hours staff continue to see only contact and qualification fields And any unauthorized financial access attempt returns HTTP 403 with correlation ID and is audit-logged And configured exceptions may grant specified non-attorney roles read-only access to selected financial fields post-engagement, per practice settings and with audit capture
Manual Override with Audit and Time-bound Review
Given a designated admin with Override permission initiates a manual financial unlock for a matter When the override form is submitted with reason, scope, and duration Then financial permissions mirror a standard unlock for the specified duration (default 72 hours, max 7 days, configurable) And dual approval is required if policy "dual_approval_required" is enabled; without second approval the override remains pending and does not unlock And the system schedules automatic re-lock at expiry and sends reminders 24 hours before to approvers and assigned attorneys And the audit log captures requester, approver(s), timestamps, reason, scope, and resulting permission changes And overrides appear in the weekly compliance report with status (active, expired, pending)
Jurisdiction-Aware Assembly Gate
"As a paralegal, I want the assembly stage to unlock only after all required jurisdictional data is complete so that documents are generated correctly the first time."
Description

A gate that unlocks the document assembly stage only when engagement is complete, conflict checks have passed, and jurisdiction-specific required fields are satisfied. Locks prior-stage fields to prevent data drift, generates a checklist of missing items, and launches the correct template set for the selected jurisdiction. Ensures e-sign-ready filings are produced with complete, validated data, reducing rework and filing delays.

Acceptance Criteria
Unlock Assembly Upon Gate Conditions Met
Given an intake record with Engagement Status = "Signed", Conflict Screening = "Pass", and all jurisdiction-required fields validated as Complete for the selected jurisdiction When a user with Assembly access opens the Document Assembly stage Then the Assembly stage is enabled within 1 second And the "Assembly unlocked" confirmation is displayed And the jurisdiction-specific template set matching the selected jurisdiction code is preselected
Block Assembly and Show Jurisdiction Checklist When Incomplete
Given an intake record missing any prerequisite (Engagement not Signed, Conflict Screening not Pass, or any jurisdiction-required field incomplete/invalid) When a user attempts to open the Document Assembly stage Then the Assembly stage remains locked and is not accessible And a checklist of missing/invalid items is displayed, grouped by stage and jurisdiction requirement, with deep links to each field And the primary call-to-action is disabled until all checklist items are resolved And an analytics event "assembly_gate_blocked" is recorded with the blocking reasons
Lock Prior-Stage Fields After Gate Opens
Given the Assembly gate is unlocked for an intake When the user navigates to Qualify, Conflict Check, or Engagement stages Then all fields in those stages are read-only for non-admin roles And attempting to edit shows a "Reset Assembly Gate to Edit" modal with Cancel and Reset options And choosing Reset re-locks the Assembly stage, clears any generated assembly package, and marks templates as stale
Jurisdiction Change Triggers Revalidation and Template Switch
Given the Assembly gate is unlocked and a jurisdiction is currently selected When the user changes the jurisdiction and saves Then the gate evaluation re-runs and the Assembly stage is set to locked And a new jurisdiction-specific checklist is generated reflecting the new requirements And any previously selected template set and draft documents are invalidated And the correct template set for the new jurisdiction is preselected once prerequisites are satisfied
Launch Correct Jurisdiction Template Set for Assembly
Given prerequisites are satisfied and the Assembly stage is opened When the system loads available templates Then only the template set mapped to the selected jurisdiction code is displayed by default And template placeholders are populated from validated intake data with 100% required-field coverage And any unmapped required placeholders are listed as blocking items in the checklist
Gate Decision Audit Trail
Given any change to Engagement Status, Conflict Screening result, jurisdiction selection, or jurisdiction-required field completeness When the gate evaluation result changes (locked to unlocked or unlocked to locked) Then an audit entry is written capturing timestamp, user, prior state, new state, and blocking/clearing conditions And the audit entry is retrievable in the intake timeline and exportable in CSV
Audit Trail & Override Workflow
"As a managing partner, I want an auditable override process with detailed logs so that compliance is demonstrable and misuse is detected and deterred."
Description

Comprehensive logging of field exposure, edits, stage transitions, and policy decisions with user, timestamp, and reason codes. Provides a controlled override mechanism requiring justification and, optionally, approval routes for sensitive actions (e.g., skipping a gate). Offers exportable reports, retention policies aligned with firm compliance needs, and alerting on anomalous access patterns to deter misuse and support audits.

Acceptance Criteria
Field Exposure and Edit Logging
Given a user views any client intake field, When the field is rendered to the user, Then an audit event is written with: eventId, timestamp (UTC ISO-8601), userId, userRole, firmId, recordId, fieldId, fieldSensitivity, stage, action=view, accessPath (UI/API), decisionSource (policy/override), and requestId. Given a user edits a field, When the update is saved, Then an audit event records beforeValueHash and afterValueHash for sensitive fields (no plaintext), diffAvailable=true/false, reasonCode if required, and action=update. Given audit storage, When events are appended, Then events are write-once append-only and each event includes prevHash to form a verifiable hash chain; When chain verification runs, Then any tampering is detected and reported. Given normal system load, When audit events are written, Then p95 write latency <= 200 ms and error rate < 0.1%; on failure, events are queued, retried with backoff, and backlog is visible in ops dashboard.
Stage Transition and Policy Decision Logging
Given a matter advances or regresses between intake stages, When a transition occurs, Then an audit event records fromStage, toStage, triggeringUserId, triggerAction, ruleSetVersion, evaluatedRuleIds, decisionOutcome (allow/deny/require-approval), and justification if provided. Given a denied transition by policy, When the user attempts the transition, Then the system blocks it, displays the reason, and logs denial with ruleId and reasonCode. Given a successful transition, When completed, Then the event links to subsequent field exposures via relationId to provide traceability. Given time synchronization, When events are logged, Then timestamps are monotonic per matter with clock skew compensated to <= 100 ms.
Override Justification and Approval Workflow
Given a sensitive action (e.g., skipping conflict check), When initiated, Then the system requires selection of a reasonCode from a managed list and a free-text justification of at least 20 characters before proceeding. Given firm approval policy requires approval, When the request is submitted, Then it routes to the correct approver group by role/office, notifies approvers, and sets status=Pending with a unique approvalId. Given an approval request, When an approver approves or rejects, Then the action is executed or blocked accordingly; decision, approverId, timestamp, and comments are logged and linked to the originating action. Given SLAs, When a request is pending > 2 hours, Then the system escalates to a secondary approver group and alerts the requester; When pending > 8 hours, Then the request auto-expires as Rejected (configurable). Given an unauthorized user, When they attempt a sensitive override, Then the system blocks the attempt, logs action=unauthorized_override, and no restricted data is exposed.
Anomalous Access Pattern Alerts
Given baseline anomaly rules, When a single user views > 50 sensitive fields across > 5 matters within 5 minutes, Then an anomaly alert is created with severity=High within 60 seconds. Given after-hours roles, When an After-Hours Staff user accesses or attempts to access financial fields outside 06:00–19:00 local time, Then an alert with severity=Medium is generated and the access is prevented if policy forbids; the attempt is logged. Given repeated failed access, When a user incurs > 3 denied access events within 10 minutes, Then the action category is locked for 15 minutes and an administrator is notified; all events are logged. Given alert delivery settings, When an alert is generated, Then in-app and email notifications are sent to designated recipients with userId, role, IP, device, action summary, firstSeen, lastSeen, and related recordIds. Given suppression controls, When an alert rule is tuned or suppressed, Then the change is audit-logged with who, when, why, and effective period.
Exportable Audit Reports
Given an authorized auditor role, When they request an audit export with filters (time range, userId, role, stage, action, fieldSensitivity, matterId), Then the system generates CSV and JSONL exports matching filters with a signed checksum and schemaVersion. Given exports <= 100,000 rows, When requested, Then generation completes within 2 minutes p95; larger exports are chunked and streamed with continuation tokens. Given least-privilege enforcement, When a non-auditor requests export, Then access is denied and the attempt is logged. Given report usage, When the export is downloaded, Then the download event is logged and the file includes a data dictionary and column descriptions in headers.
Retention and Legal Hold Compliance
Given retention settings, When configured per eventType and fieldSensitivity, Then the system enforces retention (e.g., view=2y, edit=7y) and records policy effective dates and ruleSetVersion. Given a legal hold on a matter or user, When purge runs, Then events under hold are excluded from deletion and tagged with holdId and reason. Given nightly purge, When it executes, Then a purge report is written with counts per eventType and time window; verification queries confirm deleted events are not retrievable via API or UI. Given backup policies, When backups are rotated or restored, Then audit data retention aligns with configured policies and legal holds, and hash-chain integrity is preserved. Given a right-of-access/export request for a single client/matter, When an authorized admin requests audit data, Then export returns all related events within 24 hours with integrity checks included.

Timed Reveal

Just‑in‑time unmasking for specific fields with reason codes, auto‑expiry, and optional approver routing. Temporary visibility supports urgent tasks (e.g., verifying a DOB for a filing) without permanently widening access. Every reveal is logged, reducing friction for staff and anxiety for security leads.

Requirements

Time-Bound Field Unmasking Engine
"As an intake specialist, I want to temporarily unmask specific fields for a short, defined period so that I can verify details needed to file quickly without permanently broadening access."
Description

Implements field-level temporary visibility for masked data across CaseSpark intake, conflict screening, and document assembly flows. Supports per-field sensitivity policies, default and maximum durations, concurrent session handling, and immediate re-masking upon expiry. Enables explicit per-reveal tokens that unlock only the requested field(s) and matter, with server- and client-side enforcement to prevent residual exposure (e.g., cache purge, redaction overlays). Ensures uninterrupted user workflows with inline overlays and countdown indicators while maintaining least-privilege access throughout.

Acceptance Criteria
Token-Scoped Per-Field Reveal Enforcement
Given a user U with baseline permission to view a matter M but with field X masked And a policy that allows timed reveal for field X When U requests a timed reveal for field X on matter M and provides a valid reason code Then the system issues a reveal token T bound to user U, session S, matter M, field X, and duration D And server endpoints return the unmasked value of field X only when token T is presented and valid And attempts (UI or API) to access any other field or any other matter using token T are denied with 403 and logged And client unredacts only field X; all other masked fields remain redacted And no API or UI endpoint other than the field X read endpoint returns the unmasked value while token T is active
Default, Maximum, and Extension Durations with Countdown UI
Given a sensitivity policy for field X with default duration D_default and maximum duration D_max When a user requests a reveal without specifying a duration Then the system grants duration D_default and displays a visible countdown indicator of remaining time When a user requests a duration greater than D_max Then the request is rejected with a clear validation message and no reveal is granted When a reveal is active Then the user can trigger “Hide Now” to re-mask immediately, revoke the token, and stop the countdown When the user requests an extension before expiry Then the system requires a reason code, enforces that total time does not exceed D_max, applies approver routing if configured, and updates the countdown on approval
Immediate Re-Masking and Residual Exposure Prevention on Expiry
Given an active reveal token for field X When the token expires or is revoked Then server responses immediately return the masked value for field X And all open clients re-mask field X and remove the value from in-memory cache, local storage, and DOM within 2 seconds of expiry notification And any inline redaction overlays are reapplied without requiring a full page reload And any in-progress action (e.g., document assembly) that attempts to access field X after expiry is blocked and prompts the user to request a new reveal
Concurrent Session Isolation and Revocation Propagation
Given user U has two active sessions S1 and S2 on matter M where field X is masked When U obtains a reveal token for field X in session S1 Then field X is unmasked only in S1; S2 remains masked unless a separate reveal is granted for S2 And token reuse from any other browser/device or session is rejected and logged When the reveal in S1 expires or is revoked Then no session can continue to access the unmasked value with that token, and S1 re-masks immediately
Reason Codes and Optional Approver Routing
Given a field X with a policy that requires a reason code and may require approval based on role/sensitivity When a user requests a reveal Then the user must provide a policy-compliant reason code before submission And if approval is required, the request is routed to the configured approver(s), the field remains masked pending decision, and the request auto-expires after the policy-defined timeout if no decision When an approver approves the request Then the reveal is granted for the approved duration (≤ policy maximum), and the decision is communicated to the requester When an approver rejects the request Then no data is revealed, and the requester is notified with the rejection reason
Comprehensive Audit Logging for Reveal Lifecycle
Given auditing is enabled When a reveal request is created, approved, denied, started, extended, manually re-masked, expired, or results in an access denial Then an immutable log entry is written capturing: event type, timestamp (UTC), user ID, session ID, role, matter ID, field ID, token ID (if applicable), client IP, user-agent, reason code, duration requested/granted, approver ID (if any), and outcome And each successful read of the unmasked value references the active token ID in the audit log And audit logs are queryable by security admins via UI/API and are read-only/tamper-evident
Inline Workflow Continuity Across Modules (Intake, Screening, Assembly)
Given a user is performing an intake, conflict screening, or document assembly task that requires a masked field X When a reveal is granted for field X Then the UI unblocks only field X inline without navigating away, and displays a countdown indicator adjacent to X And navigation within the same matter and session preserves the unmask state for X across modules until expiry And upon expiry or manual re-mask, all modules re-mask X immediately and any dependent steps prompt for a new reveal And summary lists, search results, and exports remain masked unless explicitly within scope of the active reveal for field X
Mandatory Reason Codes & Policy Mapping
"As a security lead, I want every reveal to include a standardized reason code so that access is justified, reportable, and enforceable by policy."
Description

Introduces a managed taxonomy of standardized reason codes required for each reveal request. Admins define codes, descriptions, and mappings that constrain which fields can be revealed, default/max duration, whether approval is required, and post-reveal obligations (e.g., attach filing ID). Supports jurisdiction-aware variants (e.g., SSN vs. DOB), freeform justification notes, and analytics on usage. Guides users to the least-privileged option with contextual suggestions and prevents reveals without a valid mapped reason.

Acceptance Criteria
Admin manages reason code taxonomy and mappings
Given I am an Admin on the Policy Settings page When I create a reason code with name, description, mapped fields, default duration, max duration, approval requirement, and post‑reveal obligations Then the reason code is saved and appears in the active code list for selection on reveal requests Given I configure jurisdiction-specific variants for the reason code (e.g., CA, NY, Federal) When I save the mappings Then each variant is restricted to its jurisdictions and is hidden outside them Given I set a default duration greater than the max duration When I attempt to save Then validation blocks the save and displays an error indicating the default must be ≤ max Given I deactivate a reason code When users open the reveal form Then the deactivated code is not selectable for new requests and remains visible in historical logs only
Enforced reason selection with least‑privilege guidance
Given a user initiates a reveal for a specific field (e.g., DOB) When they attempt to submit without selecting a reason code Then the submission is blocked with a message that a mapped reason code is required Given the selected field and jurisdiction When the user opens the reason selector Then only reason codes mapped to that field and jurisdiction are shown; unmapped codes are hidden Given multiple mapped codes exist with different privilege levels (e.g., Month/Year DOB vs Full DOB) When the user opens the selector Then the least‑privileged option is preselected and labeled as Recommended Given the user switches from the recommended least‑privileged code to a broader code When they submit Then the system requires a non‑empty justification note of at least 15 characters and records an override flag; if policy forbids overrides, the submission is blocked Given the justification note is blank or only whitespace When the user submits Then the request is blocked with an inline error until a valid note is provided
Jurisdiction‑aware reason code variants applied
Given a matter with jurisdiction set to NY When a user requests to reveal SSN Then only NY‑mapped SSN reason codes (and Global variants, if configured) are available; CA‑ or Federal‑only variants are not shown Given a matter with no jurisdiction specified When a user opens the reason selector Then only Global reason codes are shown and a prompt indicates jurisdiction is required to see local variants Given a matter with jurisdiction changed from CA to NY When the reveal form is reopened Then CA‑only variants are removed and NY‑appropriate variants are displayed
Approval routing gates reveal access
Given the selected reason code is configured to Require Approval When the user submits the reveal request Then the target field remains masked and the request status is Pending Approval with a notification sent to the approver group Given an approver reviews a pending request When they Approve Then access is granted only after approval and for no longer than the configured duration Given an approver Rejects or the request times out When the user views the request Then access is not granted and the outcome is recorded in the audit log with approver, decision, and timestamp Given the selected reason code does not require approval When the user submits the reveal request Then access is granted immediately (subject to duration and other constraints)
Duration constraints and auto‑expiry enforced
Given a reason code with default duration 5 minutes and max duration 30 minutes When the user opens the reveal form Then the duration is prefilled to 5 minutes and cannot be set above 30 minutes Given a reveal is approved/granted for N minutes When N minutes elapse Then access to the revealed field is automatically revoked and the event is logged with expiry timestamp Given the user attempts to extend an active or expired reveal session When they submit an extension without a new request Then the system blocks the action and instructs the user to submit a new reveal request
Post‑reveal obligations enforced
Given a reason code requires a post‑reveal obligation (e.g., Attach Filing ID) When the reveal session is ending or the user attempts to close it Then the user is required to provide the specified obligation data and cannot complete closure until it is provided Given the user provides the obligation data When the session closes Then the obligation values are stored, tied to the reveal record, and visible in audit/analytics Given the user abandons the session without satisfying required obligations When the auto‑expiry occurs Then the session is marked Obligations Incomplete and notifications are sent to the user to complete the required data
Usage analytics by reason code, field, and jurisdiction
Given reveal requests occur over time When an Admin opens the Timed Reveal Analytics Then they can view counts, approval rates, average granted duration, override rate (broader‑than‑recommended chosen), and obligation completion rate grouped by reason code, field, jurisdiction, and user Given the Admin sets a date range filter When they apply it Then the metrics and charts reflect only events within the selected period Given the Admin exports analytics When they download CSV Then each row contains: event timestamp, user, matter ID, field, jurisdiction, reason code, requested duration, granted duration, approval required (Y/N), approval outcome, justification present (Y/N), override used (Y/N), obligations satisfied (Y/N)
Conditional Approver Routing & Escalations
"As a practice administrator, I want sensitive reveal requests to route to the right approver with clear SLAs so that we uphold least-privilege without blocking urgent work."
Description

Adds optional approval workflows triggered by policy, field sensitivity, user role, matter type, or time of day. Supports single- and multi-step approvers, SLAs, escalation paths, delegates, out-of-office handling, and after-hours rules. Provides in-app, email, and chat (Slack/Teams) approval surfaces with one-click approve/deny and inline context. Includes emergency break-glass with stricter duration caps, extra justification, and automatic notifications to compliance watchers.

Acceptance Criteria
Policy-Triggered Single-Step Approval for Sensitive Field
Given a user with role "Intake Specialist" requests a Timed Reveal of the "DOB" field on a Family Law matter and the field is tagged High sensitivity and policy "HS-1" requires one approver for that role during business hours When the user submits the reveal with a required reason code and a free-text justification of at least 15 characters Then the system routes the approval to the designated approver per policy HS-1 and sends notifications via in-app, email, and Slack/Teams within 5 seconds And the approver can approve or deny with one click from any surface without additional navigation And upon approval the field is revealed only to the requester for 10 minutes, auto-expires, and cannot be re-revealed without a new request And upon denial the field remains masked and the requester is notified with the denial reason And the audit log records requester, approver, matter ID, field, policy ID, reason code, channels notified, decision, timestamps, and duration
Multi-Step Approval with SLA and Escalation
Given policy "HS-2" requires two-step approval (Step 1: Senior Paralegal, SLA 10 minutes; Step 2: Responsible Attorney, SLA 10 minutes) When the requester submits a Timed Reveal governed by HS-2 Then Step 1 must approve before Step 2 is notified And if Step 1 breaches its SLA, the request escalates to the delegate Senior Paralegal and then to the Paralegal Lead after an additional 5 minutes And if Step 2 breaches its SLA, the request escalates to the Duty Attorney immediately And any denial at any step terminates the workflow and notifies the requester with the denial reason And upon final approval the reveal activates with the configured duration and the workflow history shows timestamps, assignees, and escalations And the requester and admins can view real-time SLA timers and current assignee
Out-of-Office Handling and Delegation
Given the designated approver for a step is marked Out-of-Office during the requested window and has a delegate defined When the system routes the approval Then the task is assigned to the delegate instead of the primary approver and the approval surfaces display an OOO banner naming the primary And if no delegate is defined, the request routes to the approver group queue; if the group is also fully OOO, it escalates to the next-level approver per policy And approvals made by the delegate satisfy the step and are logged as "Approved (Delegate of <Primary Name>)" And no notifications are sent to the OOO primary And all reroutes occur within 2 seconds and are captured in the audit trail
After-Hours Rules and Routing
Given a Timed Reveal request is submitted between 19:00 and 07:00 tenant local time and policy "AH-1" applies When routing the approval Then require two approvers even if the standard policy requires one And notify via in-app and email only (Slack/Teams notifications suppressed after-hours) And route to the On-Call roster first; if no on-call assignee is available, escalate to the Partner-on-Call within a 10-minute SLA And cap the reveal duration at 5 minutes after-hours regardless of the requested duration And record an after-hours flag in the audit log for the request, the decision, and the reveal
Emergency Break-Glass Path
Given the requester selects Emergency Break-Glass for a High sensitivity field When they provide reason code "Emergency" and a justification of at least 50 characters and confirm an explicit risk warning Then the reveal is granted immediately without prior approval with duration capped at 3 minutes and is non-extendable And automatic notifications are sent within 5 seconds to Compliance Watchers, Responsible Attorney, and the Firm Security mailbox with full context And a mandatory post-event review task is created for Compliance with a due date of 1 business day And the requester is blocked from submitting another break-glass for the same matter and field for 60 minutes And the audit log includes the break-glass flag, justification text, recipients notified, and millisecond timestamps
Cross-Surface One-Click Approvals with First-Response Wins
Given an approval request is pending for a Timed Reveal When an approver acts from any surface (in-app, email action link, Slack/Teams button) Then the decision executes exactly once; the first response wins and subsequent attempts return an "Already decided" state within 2 seconds And the decision state synchronizes across all surfaces within 5 seconds And the approval prompt includes requester, matter, field, sensitivity, reason code, requested duration, and policy reference And the approver may add an optional comment up to 250 characters, which is included in the requester notification and audit log
End-to-End Auditability and Reporting
Given the system processes Timed Reveal requests and approvals When an admin queries the audit log by date range, user, matter ID, field, policy, decision, channel, and SLA outcome Then results for up to 10,000 records return within 3 seconds and can be exported to CSV and JSON And logs are immutable with a per-tenant cryptographic hash chain and daily anchor And the metrics dashboard displays median and 95th percentile approval times by policy and time-of-day And any missing or corrupted log segment triggers an alert to Compliance Watchers within 1 minute
Auto-Expiry, Extension, and Revocation Controls
"As a staff user, I want reveals to auto-expire with clear controls to extend or revoke so that sensitive data isn’t left exposed longer than necessary."
Description

Enforces reveal expiry via synchronized client- and server-side timers with visible countdown, automatic re-masking, and invalidation of reveal tokens. Provides pre-expiry reminders, controlled extension requests subject to policy and approval, and immediate manual revocation by approvers or admins. Purges UI caches and export buffers upon expiry/revoke and blocks copy/print where technically feasible, with event hooks to notify downstream processes.

Acceptance Criteria
Auto-Expiry Countdown, Server Sync, and Automatic Re-Masking
Given a user with permission reveals a sensitive field for a configured duration of 5 minutes When the reveal begins Then a visible countdown next to the field shows remaining time in mm:ss and updates at least once per second Given the server issues an expiry timestamp Texp and the client clock may drift by up to 2 minutes When the countdown is displayed Then the countdown is calculated from server time and remains accurate to within 500 ms of server time When the countdown reaches 00:00 or current server time >= Texp Then the field content is re-masked in the UI within 1 second and the reveal token is invalidated server-side immediately When any API call is made using the expired token Then the request is rejected with HTTP 403 and error code REVEAL_TOKEN_EXPIRED
Pre-Expiry Reminder Notifications
Given a reveal duration greater than 60 seconds When remaining time reaches 60 seconds and 10 seconds Then the user receives an in-app alert (ARIA role=alert) with the exact remaining time Given a reveal duration of 60 seconds or less When remaining time reaches 10 seconds Then the user receives a single in-app alert When a reveal is revoked before a reminder threshold Then no further reminders are shown When a reminder is shown Then a RevealReminder event is logged with reveal_id, user_id, timestamp, and remaining_seconds
Extension Request Workflow with Policy and Approver Routing
Given an active reveal with at least 10 seconds remaining and a policy allowing extensions up to a 15-minute cumulative cap in 1–5 minute increments requiring approver approval When the user requests an extension selecting a reason code and entering a justification of at least 20 characters Then the request enters PENDING state and is routed to the configured approver within 2 seconds When an approver approves a 3-minute increment within policy limits Then the new expiry extends by 3 minutes without exceeding the cumulative cap, the UI timer updates within 1 second, and the server persists the new Texp When an approver denies the request Then the expiry remains unchanged and the requester is notified in-app with the denial reason When policy auto-approves for specific reason codes Then the extension is applied immediately without approver action and is logged with policy_id Then all extension requests and decisions are auditable with actor, timestamps, previous/new expiry, reason code, and IP address
Immediate Manual Revocation by Approver or Admin
Given an active reveal When an approver or admin clicks Revoke and confirms with a reason code Then the reveal token is invalidated server-side immediately and the field re-masks in all active client sessions within 3 seconds When any client attempts to fetch the revealed value after revocation Then the API responds with HTTP 403 and error code REVEAL_REVOKED and the UI displays a Revoked badge with the reason Then a Revocation event is logged with reveal_id, revoker_id, reason_code, and timestamp
Purge UI Caches and Export Buffers on Expiry/Revocation
Given a revealed value may exist in UI memory, queued export jobs, or print previews When the reveal expires or is revoked Then the UI purges in-memory caches, clears export buffers, cancels pending downloads, and blanks print previews within 2 seconds Then subsequent client searches, scrollback, and offline access return only masked placeholders for the field Then subsequent export or print requests return redacted content and responses include Cache-Control: no-store Then an Audit event PurgeCompleted is recorded with affected_artifacts and timestamps
Copy/Print Controls and Clipboard Hygiene
Given a field is revealed When the user attempts to copy via keyboard shortcuts, context menu, or select-all Then copying and selection are blocked for the revealed field and copy-related menu items are disabled When the user initiates printing while a reveal is active Then printed output redacts the field and applies a visible watermark indicating restricted content When the reveal expires or is revoked Then any clipboard entries created by the application for this field are cleared or overwritten within 1 second where supported by the platform Then all blocked or attempted copy/print actions are logged with action type, user_id, and timestamp
Downstream Event Hooks for Expiry/Extension/Revocation
Given integrations subscribe via webhooks and message bus When a reveal expires, is extended, or is revoked Then an event is emitted within 2 seconds to all configured endpoints with an idempotency key, event type, reveal_id, user_id, previous/new expiry (if applicable), and reason_code (if applicable) When an endpoint returns a transient error (HTTP 5xx or timeout) Then delivery is retried with exponential backoff for at least 24 hours with at-least-once semantics When an endpoint processes the event using the idempotency key Then duplicate deliveries do not create duplicate side effects
Comprehensive Reveal Audit Trail & Reporting
"As a security officer, I want a complete, tamper-evident log and reports of all reveals so that I can investigate incidents and demonstrate compliance."
Description

Captures immutable, append-only audit records for every reveal: who, when, what field and matter, reason code, duration, approver path, IP/device, and geo signals. Stores no revealed values, only metadata. Provides filters, dashboards, and exports (CSV/JSON) and integrates with SIEM via webhooks/streams. Supports retention schedules and jurisdiction-specific compliance reports, plus anomaly detection hooks (e.g., unusual volume or off-hours patterns) to feed alerts.

Acceptance Criteria
Audit Record Creation on Timed Reveal
Given a timed reveal is requested for a specific field in a matter with a valid reason code and a defined visibility duration When the reveal is approved (or auto-approved per policy) and the field becomes visible Then an audit record is appended capturing: reveal_session_id, user_id, user_role, matter_id, field_id, field_label, timestamp_start (UTC ISO 8601), timestamp_expiry, reason_code, approver_path (ordered approver_ids with decision timestamps), client_ip, user_agent, device_id (if available), geoip_country/region/city, outcome="approved" And no revealed field values are stored in the audit record And when the reveal expires or is revoked, a closure event is appended with outcome="expired" or "revoked" and actual_duration_seconds And if the reveal request is denied, a denial event is appended with approver_id and reason
Append-Only Immutability and Tamper Evidence
Given an audit ledger exists with records When any user (including system admins) attempts to update or delete an existing audit record via UI or API Then the operation is blocked and a "mutation_denied" event is appended identifying actor and attempted action And each record includes a content_hash and prev_hash forming a verifiable chain And a daily integrity job recalculates hashes and publishes a verification report with status="ok" and discrepancy_count=0 And any discrepancy triggers an "audit_integrity_alert" event emitted to SIEM within 60 seconds
Audit Log Filtering, Pagination, and Export
Given an authorized auditor views the Audit Dashboard with 10,000 or more records When filters are applied (date range, user_id, user_role, matter_id, field_id, reason_code, outcome, approver_id, IP range, geo, time-of-day, duration range) Then the filtered results return within 2 seconds for datasets up to 50,000 records and include total_count and page_count And results are sortable by any column and paginated (page sizes: 25, 50, 100) And an Export action produces CSV and JSON files containing exactly the displayed records and columns, with UTC ISO 8601 timestamps, no revealed values, and a file-level checksum And dashboard widgets display KPIs (reveals by outcome, top reason codes, off-hours rate) reflecting the same filters
SIEM Webhook/Stream Integration
Given a SIEM destination is configured with a signed webhook or stream When audit events occur (requested, approved, denied, expired, revoked, integrity_alert, anomaly_detected) Then events are delivered in near real time (P95 < 5s) with at-least-once semantics and an idempotency_key And payloads are JSON, include all audit metadata fields, and are HMAC-SHA256 signed with a rotating secret; the signature is included in an Authorization header And transient failures trigger exponential backoff retries for up to 24 hours with jitter, and failures are surfaced on an integration health dashboard And delivery respects data residency and redaction policies per jurisdiction
Retention Schedules and Jurisdictional Compliance Reports
Given retention schedules per jurisdiction are configured (e.g., CA=7y, NY=6y) and legal holds may be applied at matter or organization level When a record reaches its retention expiry and is not under legal hold Then a purge marker is appended, the record payload is cryptographically shredded, and counts are updated; the marker includes purge_reason, timestamp, and actor="system" And purge operations are irreversible and appear in purge reports And compliance reports generated per jurisdiction include required fields and metrics (counts by outcome, reason codes, off-hours rate, approver usage) and produce CSV/JSON within 60 seconds for up to 100,000 records And report generation excludes revealed values, includes report metadata (jurisdiction, period, generation_time, checksum), and is reproducible from the audit ledger
Anomaly Detection Hooks for Unusual Reveal Activity
Given anomaly thresholds and baselines are configured (e.g., Z-score > 3 for hourly volume; off-hours window 19:00–07:00 local; per-user rate limits) When reveal activity exceeds thresholds or occurs in unusual patterns Then an anomaly_detected event is appended and emitted to SIEM including rule_id, metric, baseline, observed_value, window, and top contributing dimensions And alerts are deduplicated within a 15-minute window and support configurable severity and auto-resolution when activity normalizes And a simulator allows seeding synthetic events to validate detection rules and alert routing end-to-end
Admin Policy Console for Timed Reveal
"As a firm admin, I want to centrally define and test Timed Reveal policies so that the feature aligns with our roles, jurisdictions, and compliance needs."
Description

Delivers an administrative UI to configure eligible fields, sensitivity tiers, default/max durations, required reason codes, approval routing rules, notification templates, after-hours constraints, and jurisdiction-aware policies. Includes draft/preview, simulation against sample users and matters, versioning with change history, and safe rollout (scoped pilots, gradual enablement) with rollback. Surfaces policy conflicts and provides guidance to align with firm and regulatory requirements.

Acceptance Criteria
Configure Eligible Fields and Sensitivity Tiers
Given an admin with Policy Console access When they open Field Settings Then the system lists all fields from the data dictionary with current eligibility and sensitivity tier values And the admin can toggle field eligibility and assign sensitivity tiers per field And attempts to save with unmapped required fields or invalid tier values are blocked with inline errors And Save as Draft persists changes without affecting live policy And Publish requires a confirmation summarizing changes and increments the policy version And an immutable audit record is created with actor, timestamp, changeset, and version
Duration Controls and After-hours Constraints
Given sensitivity tiers support default and maximum reveal durations When an admin configures durations per tier Then the UI enforces max ≥ default and valid duration inputs And reveal requests cannot exceed the configured max; requests below default are allowed but expire at default unless shortened by policy And approved reveals auto-expire at the configured duration relative to approval time And after-hours rules (block, require approval, reduced max) are enforceable per tier and jurisdiction And all duration and after-hours decisions are logged with calculated expiry, time zone, and policy version
Reason Codes, Approver Routing, and Notifications
Given an admin defines reason codes with labels and optional required free-text justification constraints And maps reason codes and sensitivity tiers to approver routing rules (role, manager, queue) When a user submits a reveal request Then a valid reason code (and justification if required) is mandatory before submission And approvers resolve deterministically per routing rules; if none resolve, the request is blocked and an admin alert is sent And SLA and escalation timers are enforced per rule until approval/denial And notification templates are selectable per event (request, approve, deny, expire) with variable preview and placeholder validation And notifications are sent using the chosen template with delivery status recorded for each recipient
Jurisdiction-aware Policy Conditions
Given an admin can scope rules by jurisdiction attributes (country, state/province, county, court) When a matter or user matches multiple jurisdiction-scoped rules Then the most restrictive effective policy is applied using precedence: higher sensitivity > explicit jurisdiction > firm default And admins can define fallback behavior (e.g., no reveal allowed) when no matching rule exists And evaluation results (matched rules, precedence decision) are visible in simulation and audit views
Draft, Preview, and Simulation
Given an admin creates or edits a policy as a draft When they open Preview Then a read-only view shows the effective policy by field, tier, jurisdiction, and time window And the admin can run a Simulation against sample users and matters to see allow/deny, required approvals, expected duration/expiry, and notifications And simulations send no live notifications or policy changes and can be exported for review
Versioning, Change History, Safe Rollout, and Rollback
Given publishing creates a new immutable policy version with a semantic identifier When a version is published Then a change log details added/removed/modified rules and templates with actor and timestamps And the admin can compare any two versions with a side-by-side diff And rollout can be scoped to pilot audiences (users/groups/offices/matter tags) and/or percentage-based gradual enablement with start/end schedules And the admin can pause (kill switch) or roll back to a prior version; effective policies revert without data loss And all rollout actions are audited and visible in a chronological timeline
Policy Conflict Detection and Guidance
Given multiple rules may overlap or contradict When the admin saves or publishes a draft Then the system validates for conflicts (e.g., overlapping jurisdictions, inconsistent durations, duplicate field mappings) and classifies by severity (warning, error) And errors block publication; warnings allow publication only with explicit acknowledgment And guidance provides actionable remediation steps with deep links to offending rules and documentation And the conflict report is exportable and viewable in simulation for impacted users and matters
API, Webhooks, and SDK Support
"As an integrator, I want APIs and webhooks for Timed Reveal so that I can embed reveal flows into custom intake and filing automations."
Description

Exposes endpoints to request reveals, supply reason codes, approve/deny, extend/revoke, and subscribe to reveal events. Provides webhooks for state changes (requested, approved, expired, revoked) and samples for integrating with CaseSpark document assembly scripts and external tools. Implements scopes, idempotency keys, rate limits, structured error codes, and versioned contracts with backward compatibility. Supplies client SDKs and reference implementations for rapid adoption.

Acceptance Criteria
Request Reveal Endpoint with Reason Codes and Idempotency
Given a client with OAuth2 token scoped to reveals.request When the client POSTs /v1/reveals with subject_id, field_ids[], reason_code, requested_duration, and an Idempotency-Key header Then the API responds 202 with body containing reveal_request_id, status="requested", expires_at within policy bounds, and echoes the idempotency_key And the request is persisted with requester_id, reason_code, and audit metadata And a second POST with the same Idempotency-Key and identical body returns 202 with the identical reveal_request_id and no duplicate record And a POST with the same Idempotency-Key but different body returns 409 with error.code="IDEMPOTENCY_KEY_BODY_MISMATCH" And an invalid reason_code returns 400 with error.code="REASON_CODE_INVALID" And a token missing reveals.request returns 403 with error.code="INSUFFICIENT_SCOPE"
Approver Routing: Approve/Deny Reveal Request
Given a pending reveal request that requires approval by policy When an authorized approver with scope reveals.approve POSTs /v1/reveals/{id}/approve with optional justification Then the API responds 200 with status="approved", effective_at<=2s from request time, and expires_at honoring requested_duration and policy limits And subsequent duplicate approves are idempotent and return 200 with the same representation And an unauthorized approver receives 403 with error.code="NOT_APPROVER" And POST /v1/reveals/{id}/deny marks the request status="denied" with reason captured and returns 200 And requests configured as auto-approve return 409 on manual approve/deny with error.code="APPROVAL_NOT_REQUIRED" And all actions are appended to the audit trail with actor_id, action, occurred_at
Extend and Revoke Active Reveal with Audit Log
Given an active reveal with remaining time When a client with scope reveals.manage POSTs /v1/reveals/{id}/extend with additional_duration within policy max and Idempotency-Key Then the API responds 200 with a new expires_at > previous expires_at and increments extensions_count by 1 And exceeding policy max returns 422 with error.code="EXTENSION_LIMIT_EXCEEDED" And POST /v1/reveals/{id}/revoke by an authorized actor immediately ends visibility (effective<=60s) and returns 200 with status="revoked" And extend/renew on a revoked or expired reveal returns 409 with error.code="REVEAL_NOT_ACTIVE" And all extend/revoke operations are captured in the audit log including previous_expires_at, new_expires_at, actor_id, reason
Webhooks for Reveal State Changes with Signature and Retries
Given a subscriber has registered a webhook endpoint with a shared secret When a reveal transitions to requested, approved, expired, or revoked Then a corresponding event is POSTed within 5 seconds with body containing id, type, occurred_at (UTC), sequence, version, and data, and header X-Signature using HMAC-SHA256 And events are delivered at-least-once with exponential backoff retries for up to 24 hours on non-2xx and on 429; 4xx (except 429) are not retried; 410 removes the subscription And receivers can verify signatures and reject invalid ones; invalid signature attempts are not retried and logged And event ordering per reveal_id is preserved using the sequence field And webhook delivery includes Idempotency-Key to support receiver deduplication
Scopes, Rate Limits, and Structured Error Responses
Given API consumers invoke endpoints under normal and burst load When requests exceed the configured rate limit Then the API returns 429 with Retry-After and rate limit headers X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset And each endpoint enforces the minimum required scope (e.g., reveals.request, reveals.approve, reveals.manage, webhooks.manage) returning 403 with error.code="INSUFFICIENT_SCOPE" when missing And all non-2xx responses include a structured JSON error with fields: code, message, details (object), docs_url, request_id And error codes are stable and documented; unknown routes return 404 with error.code="NOT_FOUND" And all responses include a correlating Request-Id header
Versioned Contracts, SDKs, and Reference Implementations
Given clients specify X-API-Version or Accept: application/vnd.casespark.reveals.v1+json When a new minor version is released Then existing v1 integrations continue to function without breaking changes, and deprecation headers (Sunset, Deprecation) are advertised for any deprecated fields with >=90 days notice And the JavaScript and Python SDKs are published with semver, include typed clients for all endpoints, automatic retries/idempotency, and webhook signature verification utilities And quickstart samples for CaseSpark document assembly and an external tool pass end-to-end tests exercising request→approve→extend→revoke and webhook handling And OpenAPI schema is published for each version, and SDKs are generated/validated against it in CI

Access Ledger

A human‑readable audit trail that shows who viewed, edited, exported, or downloaded each sensitive field, when, and why. Includes anomaly alerts and exportable reports for malpractice carriers or audits. Builds trust with clients and gives Privacy‑First admins instant visibility into exposure.

Requirements

Field-Level Access Tracking
"As a Privacy-First admin, I want every access to sensitive fields recorded with who, what, when, where, and why so that I can prove compliance and quickly assess exposure."
Description

Log every view, edit, export, and download at the individual field level across CaseSpark modules (intake, conflict screening, document assembly, e-sign). Capture actor identity and role, matter and client context, action type, field path, timestamp with timezone, session ID, origin (web/app/API), IP/geolocation, device fingerprint, success/failure, and record/version references. Hash and optionally tokenize old/new values to avoid exposing raw PII in the log while preserving verifiability. Use a versioned event schema with at-least-once delivery to an append-only store, sub-100ms overhead per event, backpressure handling, and offline queueing. Provide SDK hooks for all data entry points and exports to ensure complete coverage. Outcome: comprehensive, performant traceability that underpins anomaly detection, reporting, and client trust.

Acceptance Criteria
Log View Event with Full Context
Given a logged-in user with role "Paralegal" views a sensitive field in the Intake module via web When the field value is retrieved and rendered Then an event is recorded within 1 second containing: actorId, actorRole, matterId, clientId, action=view, module=intake, fieldPath, schemaVersion, timestamp (ISO 8601 with timezone), sessionId, origin=web, ipAddress, geoLocation, deviceFingerprint, outcome=success, recordId, recordVersion, eventId And the append-only store contains the event with an immutable payload And at least one event exists for the view even if the value was served from cache
Log Edit Event with Hashing and Tokenization
Given tokenization for PII fields is enabled and a user with role "Attorney" edits a sensitive field via API When the edit request is processed Then the event includes valueOldHash and valueNewHash computed with the configured salted SHA-256 and does not include raw values And hashes recomputed from the submitted values match the stored hashes And the event includes: actorId, actorRole, matterId, clientId, action=edit, module, fieldPath, schemaVersion, timestamp (with timezone), sessionId, origin=api, ipAddress, geoLocation, deviceFingerprint, outcome (success/failure), recordId, previousRecordVersion, newRecordVersion, eventId
Log Export/Download Events per Field with Reason
Given a user exports a document (PDF/CSV) containing sensitive fields from Document Assembly When the export completes Then one event per exported sensitive field is recorded with action=export, module=document_assembly, fieldPath, and a shared batchId correlating all field events for the export And the event captures exportType (pdf/csv), destination (download/local/email/e-sign), user-provided reason, and contains no raw PII values And downloading an e-sign packet triggers events with action=download using the same batchId pattern
At-Least-Once Delivery and Idempotent Append-Only Persistence
Given the event sink becomes unavailable for 2 minutes When users trigger view/edit/export/download actions Then each emitted event is eventually persisted at least once with a stable eventId and immutable payload in the append-only store And duplicates (if any) share the same eventId so consumers can deduplicate And within a sessionId, events carry a monotonically increasing sequenceNumber to enable ordering guarantees on read
Performance Overhead p95 < 100ms Under Load
Given a sustained workload of 500 audit events per second for 15 minutes in staging When users perform view/edit/export/download actions across modules Then the additional latency attributable to logging is <= 100 ms at p95 and <= 50 ms at p50 per action And the system records 0 dropped events and < 1% events requiring more than 5 retries And CPU and memory overhead of logging remain within configured SLOs without throttling user actions
Backpressure and Offline Queueing Durability
Given a mobile app loses network connectivity for 10 minutes When a user continues to view and edit sensitive fields Then the SDK queues events durably to disk with no data loss within the configured queue capacity And upon reconnect, queued events flush in FIFO order preserving original timestamps and sessionId And while the sink is slow, backpressure engages without blocking user actions, and metrics/alerts report queue depth and throttle state
Cross-Module and Entry-Point Coverage via SDK Hooks
Given all modules (intake, conflict screening, document assembly, e-sign) are exercised via web, mobile app, and API When a test suite interacts with fields annotated as sensitive performing view, edit, export, and download actions Then 100% of such interactions produce corresponding events with required fields populated And newly added sensitive fields emit events automatically via SDK hooks without additional code changes And API requests missing a sessionId receive a generated sessionId to maintain continuity
Access Reason Prompt & Enforcement
"As a paralegal, I want to provide a required reason before viewing a client’s SSN so that access is policy-compliant and auditable."
Description

Require users to select a policy-defined reason (with optional free text) before sensitive fields are revealed, edited, exported, or downloaded. Support configurable reason catalogs, per-role access policies, and jurisdiction-aware constraints (e.g., attorney-client privilege, ethics rules). Enforce re-authentication for high-risk actions and a break-glass workflow that logs justification, elevates alerting, and time-bounds access. Block actions if no valid reason is provided. Persist the reason with the event and link to the matter and document version. Outcome: enforced purpose limitation and high-quality context for auditability.

Acceptance Criteria
Prompt Reason Before Viewing Sensitive Field
Given a user attempts to reveal a sensitive field in a matter And a reason catalog is configured for that action and field When the user clicks to view the field Then the system displays a modal requiring selection of a policy-defined reason from the active catalog And the free-text note field appears only if the selected reason requires it per policy And the user cannot view the field until a valid reason is selected (and required free-text is provided) And if the user cancels or closes the modal, the field remains masked and no exposure event is recorded
Enforce Per-Role Access Policies
Given role-based access policies are configured as: Attorneys may view/edit/export sensitive fields with reasons A,B; Paralegals may view/edit with reasons A; Intake may view only with reasons C And the user is authenticated as a Paralegal When the user attempts to export a sensitive field Then the export action is blocked before reason selection And a policy error is displayed indicating the action is not permitted for the user's role And no exposure or export event is recorded
Jurisdiction-Aware Reason Constraints
Given the matter jurisdiction is set to California (CA) And the policy for CA disables the reason "Marketing Outreach" for viewing PII and requires attorney role to edit SSN When a Paralegal opens the reason prompt to view a client's SSN Then the reason "Marketing Outreach" is not displayed in the catalog And if the Paralegal attempts to proceed with any reason to edit SSN, the action is blocked with a jurisdictional policy message And no edit occurs and no field value is revealed
Re-Authentication for High-Risk Actions
Given the organization policy requires re-authentication for export and download of sensitive data with a timeout of 15 minutes And the user's last successful re-authentication was 20 minutes ago When the user selects a valid reason to export a sensitive field Then the system prompts for re-authentication (SSO or password + MFA as configured) And only upon successful re-authentication does the export proceed And if re-authentication fails or is canceled, the export is blocked and no file is generated
Break-Glass Time-Bound Access
Given the user lacks a permitted reason for the requested action per role/jurisdiction policy When the user initiates the break-glass workflow Then the system requires a free-text justification of at least 30 characters And upon submission, grants time-bound access limited to 15 minutes and only for the requested action and fields And logs the break-glass event with user, justification, scope, start/end time, and correlates an elevated alert to Privacy Admins And upon expiry, access is automatically revoked and further attempts require a new break-glass
Persist Reason and Linkage in Access Ledger
Given a user views, edits, exports, or downloads a sensitive field after providing a valid reason (or break-glass justification) When the action completes Then the Access Ledger records: user ID, role, action type, field identifier, old/new values redacted as per policy, timestamp, matter ID, document/version ID (if applicable), selected reason code, free-text (if provided), jurisdiction, policy decision, and re-auth status And the record is queryable in the UI and via API by matter ID and date range And the reason and linkage appear in exported audit reports
Block Action When No Valid Reason Provided
Given a reason prompt is displayed for a sensitive action When the user attempts to proceed without selecting a reason Or provides free-text below the required minimum length for a reason that mandates justification Then the confirm/continue control is disabled And if the user tries to bypass via keyboard or API, the request is rejected with HTTP 400 and a validation error code And the field remains masked and no exposure or action event is recorded
Anomaly Detection & Alerts
"As a managing attorney, I want to be alerted to unusual access to a high-profile matter so that I can intervene before data is misused."
Description

Detect unusual access patterns in near real time using configurable rules (e.g., after-hours access, bulk exports, cross-matter browsing, access from new geolocations/devices, repeated failed attempts, access spikes on sensitive fields). Generate severity-scored alerts with evidence bundles and timelines, and notify via in-app banners, email, SMS, and Slack/Teams. Provide acknowledgement, comment, and resolve workflows, alert suppression windows, and auto-ticket creation (e.g., Jira). Maintain an audit trail of alert lifecycles. Outcome: proactive risk mitigation and rapid incident response.

Acceptance Criteria
After-Hours Access Alert Triggering
Given firm business hours are configured (e.g., 09:00–18:00) with a timezone and the After-Hours rule is enabled for sensitive fields; When a user views, edits, exports, or downloads any sensitive field outside configured business hours; Then an After-Hours Access alert is created within 60 seconds of the access event; And no alert is created for identical actions during configured hours; And the alert contains: alert ID, rule name, user ID, role, matter ID, sensitive field identifiers (names only, no values), action type, timestamp (UTC and local), IP, ASN, geolocation (city/country + confidence), device fingerprint hash, session ID; And the system debounces to at most one alert per user+matter+rule per 5-minute window; And the alert appears in the in-app Alerts list with status New and is searchable by user, matter, and time range.
Bulk Export Spike Detection
Given the Bulk Export rule is enabled with thresholds: count_threshold=500 sensitive fields OR matters_threshold=25 matters within a 10-minute window OR rate_threshold ≥ 3x the user’s 30-day median export rate; When a user initiates exports that meet or exceed any configured threshold; Then a Bulk Export Spike alert is created within 60 seconds of export completion (or upon reaching threshold for streaming exports); And the evidence bundle includes export job ID(s), start/end timestamps, counts per field type, list of matter IDs (only), file hash(es), file size(s), and initiating client app; And the alert does not fire if the export is whitelisted via a valid change ticket number attached to the export; And the alert records the download IP(s) if the file is downloaded; And only one alert is created per export job; And the alert is visible in reports and filterable by export job ID.
Cross-Matter Browsing Detection
Given the Cross-Matter Browsing rule is enabled with thresholds: window=20 minutes, distinct_matters>=10, unassigned_ratio>=0.7; When a user accesses sensitive fields from ≥10 distinct matters within 20 minutes and ≥70% of those matters are not assigned to that user; Then a Cross-Matter Browsing alert is created within 60 seconds of the threshold being met; And the alert lists the distinct matter IDs, access counts per matter, and the assigned/unassigned classification; And accesses to matters where the user has temporary delegated access with a valid delegation token are excluded; And only one alert is created per user per window per rule; And the alert is tagged with the user’s role to support tuning by role (e.g., intake vs. paralegal).
New Geolocation/Device Access Alert
Given the New Geo/Device rule is enabled with defaults: new_device=true, geo_distance_km>=100 within last 24 hours, and allowed_regions set to [firm-configured]; When a user accesses a sensitive field from a device fingerprint not seen in the last 90 days OR from a geolocation >100km from the last known location in the prior 24 hours OR outside allowed regions; Then a New Geolocation/Device alert is created within 60 seconds; And the alert includes prior device/geo reference points, IP, ASN, VPN/hosting detection flag, device fingerprint hash, and location confidence; And no alert is created if the device is marked Trusted or the session has passed step-up authentication within the last 15 minutes; And repeated accesses from the same new device/location within 30 minutes do not create duplicate alerts.
Repeated Failed Attempts Threshold
Given the Failed Attempts rule is enabled with thresholds: failures>=6 within 10 minutes on sensitive-field access attempts; When a user generates ≥6 failed attempts (e.g., authorization denied, field-level permission denied) within a 10-minute window; Then a Repeated Failed Attempts alert is created within 60 seconds of the 6th failure; And if a successful access to any of the previously denied sensitive fields occurs within 5 minutes after the alert, the alert is auto-escalated (severity band increases by one level); And the evidence includes the last 20 failure events with error codes and targets (field identifiers only); And account lockout policies (if any) are respected and referenced in the evidence; And only one alert is created per user per window per rule.
Severity Scoring, Evidence Bundle, and Timeline
Given default severity bands are Low=0–39, Medium=40–69, High=70–89, Critical=90–100, and default base scores per rule are: After-Hours=60, Bulk Export Spike=80, Cross-Matter Browsing=70, New Geo/Device=65, Failed Attempts=50; When any alert is created; Then the alert displays a numeric severity (0–100) and band; And if multiple rules contribute to the same alert, combined severity = min(100, max(base_scores) + 10×(number_of_additional_rules)); And the evidence bundle contains: ordered timeline (last 60 minutes) with millisecond timestamps, involved user(s), matter IDs, action details, IP/ASN, user agent, device fingerprint hash, geolocation with confidence, and policy references; And evidence can be exported as PDF (redacted values) and JSON within 2 minutes; And severity and evidence remain immutable once the alert is locked (post-resolution).
Notifications, Workflow, Suppression, and Auto-Ticketing
Given notification channels (in-app, email, SMS, Slack, Teams) and recipients are configured; When an alert with severity ≥ Medium is created; Then in-app banner appears within 5 seconds, email is sent within 2 minutes, SMS within 1 minute, Slack/Teams within 1 minute; And delivery outcomes (delivered, bounced, throttled) are logged per channel; And authorized users can Acknowledge, Comment, and Resolve the alert; And Acknowledge suppresses further notifications for that alert unless escalation thresholds are crossed; And Resolve requires a resolution reason code and optional comment; And a suppression window can be scheduled per rule or global (start/end time, reason); During suppression windows, alerts are recorded as Suppressed (no outbound notifications) and visible in reports; And for alerts with severity ≥ High (or matching configured criteria), a Jira ticket is auto-created within 30 seconds with linkbacks and evidence summary; And ticket creation retries up to 3 times on failure with exponential backoff; And every state change (New, Acknowledged, Investigating, Resolved, Reopened), comment, notification event, suppression action, and ticket linkage is appended to an immutable lifecycle audit trail exportable to CSV/JSON.
Human-Readable Ledger UI
"As a client, I want a readable history of who accessed my information so that I can trust how my data is handled."
Description

Provide organization-, matter-, user-, and field-level ledger views with natural-language event summaries and quick filters by actor, action, field, reason, date range, and anomaly status. Support fast search, drill-down to event details, and grouping by matter or user. Include summaries (top accessed fields, most active users) and show inline reasons and policy references. Enable exports to PDF/CSV with preserved filters, watermarks, and timestamps. Offer a client-shareable, PII-minimized view with expiring links and view tracking. Ensure accessible design and server-side pagination for large datasets. Outcome: transparent, usable visibility that builds trust and speeds reviews.

Acceptance Criteria
Ledger Scope Views & Natural-Language Summaries
Given a user with permissions to Organization A, when they open the Ledger UI and select Organization scope, then the event list includes events from all matters within Organization A and excludes events from other organizations. Given the user switches scope to a specific Matter, when the ledger loads, then only events for that matter are shown and the total count matches the applied filters. Given the user switches scope to a specific User, when the ledger loads, then only events performed by that user are shown. Given the user switches scope to a specific Field, when the ledger loads, then only events targeting that field (by key/label) are shown. Given events are listed, when rows render, then each row shows a human-readable summary including actor, action, target field, matter name, timestamp (with timezone indicator), and inline reason text; if a policy reference exists, a clickable policy tag/link is shown; if absent, the row displays “No policy reference”.
Filtering & Fast Search
Given events exist across actors, actions, fields, reasons, dates, and anomaly statuses, when the user applies any combination of filters (actor, action, field, reason keyword, date range, anomaly status), then the results reflect the logical AND of selected filters and the filter chips display active selections. Given a date range filter is applied, when the user sets start and end dates, then only events within [start, end] (inclusive) in the user’s selected timezone are returned. Given the user enters text in global search, when they submit, then matching events across actor name, matter name, field label, reason text, and policy reference are returned case-insensitively; quoted phrases match exact phrases. Given a result set up to 100k events, when a new filter or search is applied, then the first page renders within 700 ms on median and 1.5 s at p95. Given filters are applied, when the user copies the page URL, then the URL contains query parameters that, when opened in a new session, restore the same filters, sort, scope, and page size.
Drill-Down Event Details & Inline Policy References
Given a list of events, when the user clicks an event row, then a details panel opens showing event ID, actor (name, ID, role), organization, action, target field (label and internal key), matter (name and ID), timestamp (ISO 8601 with timezone), reason text, policy reference (title and link if available), IP address, user agent, and location (if resolved). Given the details panel is open, when the user clicks “Copy event ID”, then the event ID is copied to the clipboard and a confirmation toast appears. Given the user has a direct event deep link, when they open it, then the details panel loads the specific event within the current scope if authorized, or returns a 403 if unauthorized. Given an event has a policy reference, when the user clicks the policy tag/link, then the referenced policy opens in a new tab. Given RBAC rules, when a user without access attempts to open details for an out-of-scope event, then the UI hides sensitive fields and the API returns 403 without leaking PII. Given tamper-evident storage, when the details panel loads, then the event’s signature/hash verification status is displayed and must be “Valid” for unmodified records.
Grouping & Summaries
Given a filtered result set, when the user toggles Group by Matter, then events are grouped under matter headers with per-group counts and the sum of group counts equals the total results. Given Group by User is selected, when the list renders, then events are grouped by actor with per-user counts; sorting by group name and by event timestamp within groups is supported and stable. Given any filters are applied, when the user opens the Summaries panel, then “Top Accessed Fields” (top 5 by event count) and “Most Active Users” (top 5) reflect the current filters and display counts that match the list data. Given the user changes the date range, when the Summaries panel refreshes, then rankings and counts update accordingly within 700 ms median. Given no data matches filters, when the Summaries panel opens, then empty-state messaging is shown without errors.
Export with Preserved Filters, Watermarks, and Timestamps
Given a filtered and scoped view, when the user exports to CSV, then the file contains all columns visible in the list plus event ID and includes only rows matching the current filters, scope, and sort order. Given a filtered and scoped view, when the user exports to PDF, then the document includes a header with organization, scope, filter summary, requester, and UTC timestamp; each page shows a watermark “Confidential – CaseSpark Access Ledger”, page numbers, and generation timestamp. Given an export is generated, when the user downloads it, then the filename includes organization slug, scope, date range, and an ISO 8601 UTC timestamp. Given datasets > 50,000 rows, when exporting to CSV, then the system streams or chunks the export without timeouts and completes under 2 minutes for 1 million rows at p95. Given the user lacks export permission, when they open the ledger, then the Export buttons are disabled and attempting the export endpoint returns 403.
Client-Shareable PII-Minimized View with Expiring Link & View Tracking
Given a staff user configures a shareable client view, when they generate a link, then the shared view redacts PII (names, emails, phone numbers, SSNs) and replaces them with category labels while retaining event timing, action, and reason/policy info relevant to the client. Given a link is created with a 7-day expiry, when a client opens it before expiry, then the view loads and an access event is logged with timestamp and IP; after expiry, the link returns HTTP 410 and an attempted-access event is logged. Given a link is revoked by staff, when a client attempts access, then access is denied immediately with HTTP 410 and the attempt is logged. Given a shareable view is opened, when the client interacts, then export options are limited to PII-minimized PDF and include a client-visible watermark and timestamp; CSV export is not available. Given the shareable token is leaked, when an unauthorized party accesses it, then only the minimized dataset is visible and no admin-only fields (IP, user agent, internal IDs) are exposed.
Accessibility & Server-Side Pagination for Large Datasets
Given the ledger UI, when navigated with keyboard only, then all interactive controls (scope tabs, filters, search, grouping, summaries, export, pagination) are reachable in a logical order with visible focus indicators and operable via Enter/Space. Given a screen reader is used, when the list updates due to filter or pagination changes, then the change is announced and table headers/controls have meaningful labels and ARIA attributes. Given contrast requirements, when rendered in default theme, then text and interactive elements meet WCAG 2.2 AA contrast ratios (>= 4.5:1 for normal text). Given a dataset of 1,000,000 events, when paging with server-side pagination (page sizes 25/50/100/500), then time to first page is <= 1.5 s p95 and subsequent page changes are <= 800 ms p95; filters and sorts persist across pages. Given the user changes page size or jumps to a specific page, when the list reloads, then the correct items are shown and the URL reflects page and size for sharability.
Audit & Carrier Report Generator
"As a firm owner, I want exportable audit reports that carriers accept so that renewals and audits are faster and less risky."
Description

Create one-click and scheduled reports tailored to malpractice carriers and audits, summarizing access counts by user/role, reason distributions, export/download events, anomalies and resolutions, and policy exceptions over a defined period. Include WORM export with cryptographic hashes, digital signatures, chain-of-custody metadata, and a data dictionary. Support PDF, CSV, and JSON formats and secure delivery (SFTP/secure links) with access controls and expiration. Provide report templates and branding, timezone normalization, and reproducibility via saved filters. Outcome: faster renewals and audits with defensible, standardized documentation.

Acceptance Criteria
One-Click On-Demand Carrier Report
Given an authorized Privacy‑First admin is on Access Ledger > Reports When they select the “Carrier Renewal” template, choose a date range, and click “Generate Now” Then a report is created with a unique Report ID and timestamp And the report includes sections for: access counts by user and role; reason distributions; export/download events; anomalies (open/closed) with resolution user and timestamp; and policy exceptions And the report is available in PDF, CSV, and JSON formats in the same job And aggregate totals and counts are consistent across all formats And a generation audit entry is recorded with who, when, why, and parameters used
Scheduled Report Delivery with Secure Distribution and Expiration
Given an authorized admin configures a schedule with a saved filter, template, output formats, delivery method (SFTP and/or secure links), recipients, frequency, timezone, and link expiration When the schedule triggers at the configured time Then the report is generated using the saved filter and template version referenced by the schedule And the report is delivered over SFTP using the configured host, port, and key and/or secure links are sent to recipients And secure links require authentication and expire at the configured time; after expiration, access returns 410 and is denied And delivery attempts, successes, failures, and retries are logged; failures notify the admin And a schedule history shows last/next run, status, and links to delivered artifacts
Timezone Normalization and Period Accuracy
Given a reporting timezone is selected for a report covering a start and end date When the report is generated Then all timestamps in all formats are normalized to the selected timezone and display the UTC offset And event inclusion honors the start/end boundaries in the selected timezone (including DST transitions) And the report metadata declares the reporting timezone and the inclusive time window used And sample events spanning a DST change appear in the correct day and hour buckets
WORM-Sealed Export with Hashes, Digital Signature, and Chain-of-Custody
Given the “WORM export” option is enabled for a report When the report job completes Then the output includes an immutable archive containing all report files and metadata And a manifest lists each file with its SHA‑256 hash And a detached digital signature and public certificate chain are included for the manifest And signature verification of the manifest succeeds And the chain-of-custody record includes generator identity, generation timestamp, storage location, and all delivery events And modifying any file after generation causes manifest hash mismatch and signature verification failure
Report Templates, Branding, and Versioning
Given default templates exist for “Carrier Renewal” and “Audit” When an admin applies firm branding (logo, header, colors) and saves a new template version Then a preview renders with the branding and layout as saved And generated reports display the selected branding and template version in the header/footer And template changes are versioned and immutable; scheduled jobs reference a specific template version And deleting or updating templates does not change previously generated reports
Saved Filters and Reproducibility
Given an admin saves a filter (date range definition, user/role filters, event types) as a named, versioned object When two reports are generated with the same template, saved filter version, and identical parameters against the unchanged dataset Then the resulting outputs are byte‑for‑byte identical And report metadata includes the saved filter ID, filter version, parameters digest, and an as‑of timestamp And changing any parameter or filter version produces a different parameters digest and different outputs And saved filters can be reused by schedules and one‑click runs
Data Dictionary and Schema Consistency Across Formats
Given a report is generated in PDF, CSV, and JSON When the deliverables are inspected Then a machine‑readable data dictionary (JSON) is included describing each field (name, type, units, allowed values, description) And the PDF includes a Data Dictionary appendix consistent with the machine‑readable dictionary And CSV headers and JSON keys match the dictionary exactly And a schema version is present in all outputs and in the dictionary And automated validation against the dictionary passes for CSV and JSON files
Tamper-Evident Storage & Retention
"As a compliance officer, I want the access ledger to be tamper-evident and retained per rule so that it stands up to legal scrutiny."
Description

Store ledger events in an append-only, cryptographically chained log with periodic external timestamp anchoring and WORM-compatible storage. Encrypt data in transit and at rest with managed key rotation, and replicate across availability zones. Implement jurisdiction- and matter-type retention policies, legal holds, and verified purge workflows. Provide integrity verification tools, continuity tests, and disaster recovery targets (RPO/RTO). Log administrative actions on the ledger itself. Outcome: a defensible, forensically sound record that withstands legal scrutiny.

Acceptance Criteria
Append-Only Cryptographically Chained Ledger
Given an initialized ledger, When a new event is written, Then the event includes a cryptographic hash of its payload and the previous event’s hash, And the ledger returns a monotonically increasing sequence ID and RFC3339 UTC timestamp with microsecond precision. Given existing events E1..En, When any attempt is made to modify or delete Ei, Then the operation is rejected, returns 403/CONFLICT, and a denied-action audit event is appended. Given a verification run over the last N (>= 100,000) events, When the chain-verification tool is executed via CLI and API, Then it completes within 5 minutes and reports “OK” with the root hash, Or on mismatch it reports the first divergent index and emits a Critical alert within 60 seconds. Given duplicate write attempts with the same idempotency key within 1 minute, When the second attempt occurs, Then the ledger returns the original event metadata without creating a new event. Given a request for an export, When a proof package is generated, Then it contains the event range, Merkle/chain root hash, tool version, and verification instructions.
Periodic External Timestamp Anchoring
Given the anchoring service is enabled, When the schedule interval elapses (default 15 minutes, configurable 5–60), Then a cumulative digest of all unanchored events is anchored to an external trusted time source (RFC3161 TSA or public blockchain) and a receipt is stored. Given a successful anchor, When an auditor requests proof, Then the system can export an anchor receipt (JSON and PDF) containing the digest, time, provider, and verification steps, And the receipt validates independently using the provider’s public data. Given an anchoring failure, When 3 consecutive attempts fail, Then a High-severity alert is created and sent to on-call within 2 minutes, And the system retries with exponential backoff until success, preserving the original digest. Given a service outage, When connectivity is restored, Then missed digests are anchored in order without skipping, preserving digest continuity. Given an anchor receipt, When the verification tool is run offline, Then it confirms the anchored time is within ±60 seconds of the provider’s trusted time and matches the reported digest.
WORM Storage with Compliance Retention
Given jurisdiction- and matter-type retention policies, When a ledger object is written, Then it is stored on WORM-compatible storage (e.g., S3 Object Lock Compliance mode) with a retention expiration computed from the policy and recorded on the event. Given a retained object, When any user (including admins) attempts deletion or overwrite before expiration, Then the storage layer denies the operation and the denial is logged as a ledger event. Given a legal hold is applied to a matter, When retention would otherwise allow deletion, Then the object remains undeletable until the hold is released, And hold placement and release are each appended as ledger events with actor, reason, and time. Given a retention report request, When generated, Then the report lists objects by matter, jurisdiction, retention expiration, and hold status, and can be exported as CSV and JSON.
Encryption In Transit and At Rest with Managed Key Rotation
Given any client or service connection, When data is transmitted, Then TLS 1.2+ (prefer TLS 1.3) is enforced with strong cipher suites and HSTS enabled, And connections failing policy are rejected and logged. Given ledger data at rest, When stored, Then it is encrypted using AES-256 with a cloud KMS–managed CMK, And all backups and replicas use the same or stronger encryption. Given key rotation is scheduled (at least annually) or manually initiated, When rotation completes, Then all new writes use the new key version, existing data remains decryptable, and a rotation-complete event is appended to the ledger. Given a post-rotation validation, When the automated decrypt-read test runs against 100 randomly sampled objects, Then 100% succeed, Or on any failure the system rolls back the key for affected paths and raises a Critical alert.
Multi‑AZ Replication, Continuity Tests, and DR Targets
Given normal operation, When events are written, Then they are synchronously committed to a quorum across at least 3 availability zones with a median write latency ≤ 150 ms. Given a single‑AZ failure simulation, When a failover drill is executed quarterly, Then read/write operations continue without manual intervention, measured RPO ≤ 5 minutes and RTO ≤ 30 minutes, and a continuity report is generated and archived. Given a regional network partition, When connectivity is restored, Then replicas converge without manual data repair and chain verification returns “OK”. Given DR testing, When the ledger is restored from backups to a clean environment, Then end‑to‑end integrity verification passes for the restored range and the gap to the last live write is ≤ stated RPO.
Retention Policies, Legal Holds, and Verified Purge Workflow
Given configurable policies by jurisdiction and matter type, When a matter is closed, Then retention start is computed (e.g., close date) and applied to all associated ledger objects with the correct durations per policy. Given a legal hold is active, When a purge is requested, Then the system blocks the purge and informs the requester that a hold exists, logging the denial as a ledger event. Given retention has expired and no holds exist, When a purge is initiated, Then a two‑person approval workflow is enforced, the purge produces a cryptographic manifest (hashes of deleted objects), and a purge summary report is generated and archived. Given a post‑purge verification run, When the integrity tool scans references, Then no live pointers to purged objects remain, and the manifest hashes are absent from storage while their metadata events persist in the ledger.
Administrative Actions Logged on the Ledger
Given an administrative change (e.g., policy edit, key rotation trigger, hold placement, purge approval, anchor schedule change), When the action is executed, Then a corresponding ledger event is appended containing actor identity (OIDC/SAML subject), time, IP, reason, before/after values (hashed if sensitive), and outcome. Given an attempt to suppress or delete an administrative event, When executed, Then the system rejects the operation and records the denial as a ledger event. Given an audit request, When exporting admin events for a date range, Then the system produces a signed, paginated report with chain proofs that validates end‑to‑end using the verification tool.
Role-Based Visibility & Privacy Controls
"As a Privacy-First admin, I want to control who can see ledger details and how much is revealed so that we meet privacy obligations while enabling oversight."
Description

Define granular permissions for viewing, exporting, and sharing ledger data, enforcing least privilege. Allow admins to redact or minimize PII (e.g., mask client identifiers, obfuscate IP/device) for certain roles or client-facing views while keeping event metadata intact. Provide a sensitivity classification manager to mark fields as sensitive across intake workflows and document templates, including custom fields via API. Track and audit access to the ledger itself. Outcome: targeted oversight without overexposing sensitive data, aligning with privacy obligations and client expectations.

Acceptance Criteria
Admin Defines Role-Based Ledger Permissions
- Given an admin has created roles with specific permissions for viewing, exporting, and sharing Access Ledger data, when a user with each role opens the ledger UI or calls the ledger API, then only permitted actions are available and non-permitted actions return HTTP 403 and are logged as denied with user, role, action, timestamp, and reason "insufficient_permissions". - Given a field is marked Sensitive, when a user without "view_sensitive_fields" permission views the ledger entry, then the field value is masked and the masking indicator is shown, and the underlying value is not sent to the client or included in API responses. - Given a permission change is saved by an admin, when the same user refreshes the UI or repeats the API call, then the new permissions take effect within 60 seconds across UI and API.
PII Redaction for Client-Facing Views
- Given an admin configures a redaction policy for Client and External roles to mask client identifiers and obfuscate IP/device fingerprints, when those roles view ledger entries, then sensitive values are replaced with masked tokens while event metadata (actor, action, timestamp, reason) remains visible. - Given a user in a redacted role exports or shares ledger data, when the export is generated, then the same redaction policy is applied to the exported dataset. - Given network inspection or direct API calls by a redacted role, when responses are returned, then original sensitive values are never included server-side (verified by API trace), and attempts to bypass redaction are denied and logged.
Sensitivity Classification Manager Tags Fields
- Given an admin marks a field as Sensitive via the classification manager (UI) or API, when that field appears in intake workflows, document templates, or the ledger, then redaction and permission rules are automatically enforced consistently in all surfaces. - Given a custom field is created via API with sensitivity=true, when a paralegal without sensitive-field permissions retrieves related ledger entries, then the custom field values are masked. - Given a classification change is made, when an audit report is viewed, then the change is recorded with who, when, old/new sensitivity, and affected assets count; and enforcement changes are active within 60 seconds.
Controlled Export of Ledger Data
- Given a user initiates an export of Access Ledger data, when the user lacks the "export_ledger" permission, then the export is blocked with HTTP 403 and a denied audit event is recorded with attempted scope and timestamp. - Given a user with "export_ledger" permission starts an export, when prompted for a purpose, then the export cannot proceed until a non-empty purpose of at least 10 characters is provided, and the purpose is stored with the export event. - Given an export completes, when the file is generated, then the data reflects the requester's role-based redaction policy, and the system records who, when, record count, and a SHA-256 checksum of the file in the audit log.
Audit Access to the Ledger Itself
- Given any user opens the Access Ledger screen or queries the ledger API, when the request is processed, then an audit event is recorded including user ID, role, action (view/query), timestamp, client IP (subject to role-based obfuscation), and optional reason code. - Given the organization requires a reason for ledger access, when a user attempts to access without providing a reason, then access is blocked until a reason is supplied and the reason is stored with the audit event. - Given an admin filters ledger-access events, when applying filters by user, role, timeframe, and action, then the results load within 3 seconds for up to 50k events and are exportable subject to export permissions.
API Enforcement of Least-Privilege and Redaction
- Given an API token with scopes ledger.read but without view_sensitive_fields, when requesting ledger entries, then the response excludes or masks sensitive fields and includes a redaction_applied=true flag. - Given an API token without ledger.read, when calling ledger endpoints, then the API returns HTTP 403 and logs a denied access event with token ID and scope deficiency. - Given a custom field marked Sensitive exists, when a third-party integration retrieves entries via API, then that field is masked unless the token has view_sensitive_fields, and any export endpoint applies the same rules.

Drift Guard

Continuous monitoring for permission creep. Compares current roles to baseline templates, flags risky changes, and offers one‑click rollback or scheduled attestation. Safely evolve roles as workflows change while preventing accidental over‑permissioning across the firm.

Requirements

Real-Time Permission Drift Detection
"As a firm administrator, I want continuous detection of permission changes so that I’m alerted to unintended over-permissioning before client data is exposed."
Description

Continuous background service that snapshots effective permissions for users and roles, compares them to designated baseline templates, and identifies deviations within minutes. Supports inheritance-aware diffs, cross-source changes (in-app admin edits, IdP/SCIM syncs), and scoped monitoring by office, matter type, and practice area to reflect law-firm hierarchies in CaseSpark. Stores baselines per environment (prod/staging) and per tenant, with configurable detection intervals and thresholds. Handles transient changes with debounce logic to reduce false positives, and normalizes capabilities to CaseSpark’s permission taxonomy (e.g., access to conflict results, sealed filings, draft motions, e-sign artifacts).

Acceptance Criteria
Drift detected within configured interval (in-app admin change)
Given tenant T in prod has a baseline snapshot for user U and role R And detection interval is set to 5 minutes and threshold is 1 capability When an in-app admin grants the capability sealed_filings.read to U Then a drift record for U is created within 5 minutes And the diff lists +sealed_filings.read And the record includes entity_type:user, source:in-app, environment:prod, tenant:T, timestamp And the effective-permissions snapshot at detection time is stored and versioned
Inheritance-aware effective diff for role changes
Given baseline templates define practice-area role P as a parent of role R And user U is assigned role R When capability conflict_results.view is added to P Then a drift event is created within the configured interval And U’s diff shows +conflict_results.view with inherited_from:P And no duplicate entries for the same capability appear due to inheritance
Detect SCIM/IdP-induced drift
Given tenant T has a baseline for user U And threshold is 1 capability When an IdP/SCIM sync removes capability esign.artifacts.write from U via group membership change Then a drift event for U is created within the configured interval And the diff lists -esign.artifacts.write And the event source is idp_scim and includes the IdP event reference
Scoped monitoring by office, matter type, and practice area
Given monitoring scope is configured to Office=NY, PracticeArea=Family Law, MatterType=Divorce When a permission change occurs for a user in Office=SF Then no drift event is generated When the same permission change occurs for a user in Office=NY and PracticeArea=Family Law and MatterType=Divorce Then a drift event is generated referencing the configured scope
Baseline isolation per tenant and environment
Given tenant A has separate baselines for staging and prod When a permission change occurs in staging for tenant A Then a drift event is generated using the staging baseline and environment:staging And no event is generated in prod for the same change And no event is generated for tenant B
Debounce transient permission changes
Given debounce window is configured to 2 minutes When capability draft_motions.edit is added to user U and removed within 2 minutes Then no drift event is generated When capability draft_motions.edit is added and remains for longer than 2 minutes Then exactly one drift event is generated
Normalization to CaseSpark permission taxonomy
Given external permission strings are mapped to CaseSpark capabilities When an external change references resource=sealed_filing action=read Then the drift diff records the capability as sealed_filings.read And the event metadata indicates normalization=true and mapping_source=external
Role Baseline Templates & Versioning
"As a managing partner, I want to maintain versioned role baselines so that we can evolve access safely and trace who approved each change."
Description

Provide a versioned repository of role templates that define least-privilege access for common CaseSpark personas (Intake Coordinator, Paralegal, Associate, Partner). Allow firms to customize and branch templates by office and jurisdiction, track change history with diffs and approver notes, and designate one version as the active baseline per scope. Support import/export (JSON) for change control, locking of baselines for attestation cycles, and mapping of each template permission to CaseSpark capabilities and data classes.

Acceptance Criteria
Versioned Template Creation, Diffing, and Approval Notes
Given a default persona template exists (e.g., Associate) at version v1 When an authorized admin adds or removes permissions and saves changes Then the system creates a new immutable version (e.g., v2) with timestamp, editor identity, and a required approver note And the change history displays a diff enumerating added, removed, and modified permissions and a risk delta score And the previous version remains view-only and is not altered And the new version remains inactive until explicitly set as the active baseline for one or more scopes
Scoped Branching by Office and Jurisdiction with Active Baseline Selection
Given a base template (e.g., Associate v2) is available When an admin creates a branch for Office=NY and Jurisdiction=NY Then the branch inherits all base permissions and metadata and allows scoped overrides And the UI displays the delta versus base (adds/removals/overrides) And the admin can set the active baseline per scope: Global, Office, Jurisdiction, or Office+Jurisdiction And the effective baseline resolution order is Office+Jurisdiction > Office > Jurisdiction > Global And querying the effective baseline for a user in Office=NY, Jurisdiction=NY returns the scoped branch version set as active
JSON Import/Export with Schema Validation and Round-Trip Fidelity
Given a template or branch exists When an admin exports it Then the system produces JSON conforming to CaseSpark Role Template Schema v1 including version ID, scope, permission list, capability/data-class mappings, approver notes, and a checksum When an admin imports a previously exported JSON Then the system validates schema and checksum and verifies all referenced capabilities and data classes exist; otherwise the import is rejected with actionable error messages And a successful import creates a new version or branch whose effective permissions and mappings are identical to the source And an export→import→export round trip yields JSON that is identical except for system-generated IDs and timestamps
Baseline Locking for Attestation Cycles
Given a baseline is scheduled for an attestation window from D1 to D2 When the window is active Then edits to the locked baseline are blocked for non-attestation admins with an explanatory message And attempted changes are not applied and are not partially saved And an attestation admin can temporarily unlock with a required reason, and all actions (lock, unlock, attempted edit) are audit-logged with user, timestamp, and reason And lock status is visible in list and detail views and via API And at D2 the baseline auto-unlocks and an audit event is emitted
Permission Mapping to Capabilities and Data Classes
Given a template is being edited When a permission is added or modified Then the editor must select a valid CaseSpark capability and data class mapping before saving And save is blocked if any permission lacks a mapping or references an unknown capability or data class, with inline error details And the template must show 100% mapping coverage before it can be set as an active baseline And API requests to activate a baseline with incomplete or invalid mappings are rejected with 4xx responses and error details
One-Click Rollback to Prior Baseline Version
Given an active baseline at version v5 for Office=NY, Jurisdiction=NY When an admin selects Rollback to version v4 and confirms with a reason Then the system activates v4 for the same scope within 10 seconds and records an audit log with actor, reason, previous version ID, and new version ID And watchers for that scope receive notifications (in-app and email) of the rollback And the effective permissions after rollback exactly match those of v4 And if the baseline is locked, rollback is blocked for non-attestation admins and allowed only for attestation admins with captured reason
Risk Scoring & Policy Rules
"As a compliance officer, I want risk-scored drift alerts so that I can prioritize and address the most dangerous changes first."
Description

Implement a rule engine that assigns risk scores to detected drifts based on severity, data sensitivity, and firm policy. Include default policy packs tuned for family-law workflows (e.g., access to sealed records, juvenile matters, domestic violence filings) and allow custom firm rules, thresholds, and exceptions. Display human-readable rationale for each score and suggested remediation (rollback, request approval, attestation), and support auto-flagging for mandatory review when thresholds are exceeded.

Acceptance Criteria
Baseline Drift Risk Scoring Computation
Given a detected permission drift with inputs: severity (High|Medium|Low), data_sensitivity (Restricted|Confidential|Internal|Public), and matched firm policy rules When the risk engine evaluates the drift Then a numeric risk_score between 0 and 100 inclusive is produced And the same inputs always produce the same risk_score (deterministic) And factor weights are applied as configured for the active policy set And the score, factor breakdown, contributing rules, and evaluation timestamp are persisted to the audit log
Default Family-Law Policy Pack Activation
Given an administrator enables the "Family Law Default" policy pack versioned release When the pack is activated for the tenant Then rules addressing sealed records, juvenile matters, and domestic-violence filings are loaded and active And jurisdiction-specific modifiers are applied when matter jurisdiction metadata is present And the pack’s rules are read-only and can be viewed with titles, descriptions, severities, and weights And disabling the pack restores the prior active rule set without removing any custom firm rules
Custom Rule Authoring With Thresholds and Exceptions
Given an administrator with policy-manage permissions defines a custom rule with condition(s), weight (0–100), review_threshold, and exceptions (users, roles, case types, jurisdictions) When the rule is saved Then validation enforces required fields, unique rule key, and numeric ranges And precedence is applied such that explicit exceptions override matches and custom rules override default pack rules when both match And the rule becomes active for new evaluations within 60 seconds And an in-product simulation shows expected score deltas for a sample drift before publishing
Human-Readable Rationale Rendering
Given a drift has been evaluated and scored When a user opens the drift details view Then the UI displays a human-readable rationale including matched rules, per-factor contributions, weights, thresholds used, final score, and suggested remediation And the rationale is plain language under 300 words and free of internal rule IDs by default (IDs available via expand) And the content respects the user’s locale for numbers/dates and is accessible to screen readers And a link to the applicable policy pack version and custom rule references is provided
Auto-Flagging for Mandatory Review on Threshold Breach
Given a firm-wide risk_review_threshold is configured And one or more rules are tagged as Mandatory Review When a drift’s risk_score >= risk_review_threshold or a matching rule is Mandatory Review Then the drift status is set to Requires Review And a notification is sent to the approver group within 60 seconds And the drift appears in the Review Queue with filterable reason (Threshold Breach | Mandatory Rule) And audit log records the auto-flag event with score, threshold, and triggering rule(s)
Suggested Remediation Options and One-Click Flows
Given a scored drift is displayed to a user with remediation permissions When suggested actions are generated Then options include Rollback, Request Approval, and Schedule Attestation ranked per policy preference And each option includes a brief justification and expected risk impact And selecting an option launches the appropriate flow with pre-filled context (affected permissions, users, rules, rationale) And actions disallowed by policy are disabled with a clear reason tooltip
Risk Recalculation After Policy/Threshold Changes
Given active drifts exist in the system When a default policy pack version is updated or a custom rule/threshold/exception is created, edited, or disabled Then all affected drifts are re-evaluated within 5 minutes And previous scores and rationales are retained with policy version stamps for audit And users are notified if any recalculated drift crosses into or out of Requires Review And the rationale clearly indicates the policy version used in the latest evaluation
One-Click Rollback with Safe Simulation
"As an IT admin, I want a safe one-click rollback with a preview of changes so that I can quickly remediate over-permissioning without disrupting active matters."
Description

Enable immediate reversion of a user or role to the last compliant baseline with a single action. Provide a pre-rollback simulation that previews impact, dependencies, and potential workflow breakage (e.g., open filings, pending e-sign tasks), plus bulk rollback for multi-user drifts. Require justification and optional ticket linkage, log all actions immutably, and allow scheduling of rollbacks during low-traffic windows with automatic notifications to affected users.

Acceptance Criteria
Immediate Single-User Rollback to Last Compliant Baseline
Given a drift-flagged user with a recorded last compliant baseline When an admin clicks "Rollback Now" and confirms Then the user's effective permissions are reverted to the baseline within 60 seconds and a success message with an audit link is displayed And any permissions not in the baseline are removed and any missing baseline permissions are restored; no other account attributes are changed And a post-rollback permission comparison yields a 100% match to the baseline template
Pre-Rollback Safe Simulation Preview
Given a drift-flagged user or role When an admin clicks "Simulate Rollback" Then a modal renders within 3 seconds showing: permission diff (added/removed), impacted workflows (counts of open filings and pending e-sign tasks), dependent integrations/APIs affected, and an overall risk level And the admin can export the simulation as PDF and JSON and close the modal without side effects; no permissions change during simulation
Bulk Rollback for Multi-User Drift
Given an admin selects 2–200 drift-flagged users When the admin executes "Bulk Rollback" Then each user's permissions are reverted to their respective last compliant baselines with per-user atomicity, and a completion report shows counts of successes, failures, and total duration And the batch processes at an average throughput of at least 20 users per minute And failures do not roll back successful users and include actionable error messages per user
Mandatory Justification and Optional Ticket Link
Given an admin initiates an immediate or scheduled rollback (single, bulk, or role) When the admin attempts to confirm Then the system requires a justification of at least 10 characters and validates an optional ticket URL (http/https); otherwise the Confirm action is disabled And the justification and ticket link are saved with the rollback record and visible in audit entries
Immutable Audit Logging of Simulation and Rollback Actions
Given any simulation, rollback, schedule creation/modification, or cancellation occurs When the action is saved or executed Then an append-only audit entry is created containing actor, UTC timestamp, target user/role IDs, baseline ID, permission diff hash, justification, ticket URL, result (success/failure), and request IP And audit entries expose a verification endpoint returning integrity via hash-chain; entries are non-editable and non-deletable via UI or API
Scheduled Rollback in Low-Traffic Window with Notifications
Given an admin schedules a rollback with a start time and time zone When the window begins Then the system executes the rollback within the scheduled window and sends notifications to affected users via email and in-app: 60 minutes before, 5 minutes before, and upon completion, including reason and link to details And the scheduler respects configured blackout windows and prevents scheduling that overlaps a blackout with a clear validation message
Immediate Role Rollback and Propagation to Members
Given a role has drifted from its baseline template and has active members When an admin clicks "Rollback Role" and confirms Then the role's permission set is reverted to the baseline and propagated to all current members within 5 minutes, without altering users' direct (non-role) permissions And the pre-confirmation simulation lists the number of affected members and impacted workflows; after rollback a report lists members updated and any propagation errors
Scheduled Access Attestation Campaigns
"As a practice lead, I want scheduled access attestations so that our team’s permissions stay aligned with current responsibilities."
Description

Create recurring certification campaigns that route users’ access reviews to the appropriate reviewers (manager, matter owner, or partner) with due dates, reminders, and escalations. Support approve/revoke/modify actions, capture rationale, and apply changes automatically or queue them for admin review. Provide real-time campaign progress, evidence capture for audits, and optional auto-revocation of stale roles on non-response.

Acceptance Criteria
Create Recurring Campaign With Reviewer Routing
- Given I am an admin configuring a campaign, When I set a recurrence (weekly, monthly, quarterly, or custom CRON) and timezone, Then the system schedules the next run at the correct cadence in the specified timezone. - Given reviewer routing rules (manager, matter owner for matter-scoped roles, partner as fallback), When subjects are resolved, Then each subject is assigned to the correct reviewer per rule, and any unresolved subjects are flagged with a reason. - Given a configured scope (departments, matters, roles), When I click Preview, Then the preview shows total subjects, per-reviewer counts, and exceptions, and these counts match the launched campaign. - Given launch is attempted, When zero subjects are resolved or no reviewer can be assigned, Then launch is blocked with a clear validation message. - Given the campaign is saved, When I view its definition, Then all settings (scope, routing, recurrence) are persisted and readable via UI and API.
Due Dates, Reminders, and Escalations
- Given a campaign with a due date offset (e.g., 14 days from launch), When the campaign launches, Then each review task shows the correct due date and local timezone. - Given reminder rules (e.g., 3 and 1 days before due; 1, 3, 7 days after due), When each threshold is reached, Then in-app and email reminders are sent, logged to the campaign timeline, and visible in task history. - Given an escalation rule (e.g., 3 days past due to partner), When a task exceeds the overdue threshold, Then it is escalated to the designated escalatee, reassigned if configured, and both parties are notified with audit entries created. - Given business hours/calendar settings, When reminders/escalations are scheduled, Then they respect those settings (no sends outside configured windows) and roll to the next window. - Given the dashboard, When due dates approach or pass, Then task status reflects On Track, Due Soon (<48h), or Overdue accurately in real time.
Approve/Revoke/Modify Actions and Rationale Capture
- Given a reviewer opens a task, When they select Approve, Then the decision saves with timestamp, and rationale is optional. - Given the reviewer selects Revoke or Modify, When they attempt to submit without rationale, Then submission is blocked and a rationale field is required. - Given Modify is selected, When changes are specified (add/remove specific roles or adjust role scopes), Then the system captures the exact delta requested. - Given any decision is submitted, Then the audit record includes reviewer identity, subject, roles reviewed, action taken, rationale (if provided/required), and before/after snapshots with timestamps and IP. - Given partial decisions, When a subject has multiple roles, Then the reviewer can take different actions per role and the UI prevents submission until all roles have an action or are explicitly deferred if deferral is enabled.
Auto-Apply vs Admin Review Workflow
- Given campaign application mode is Auto-Apply, When a reviewer submits Revoke/Modify decisions, Then the platform applies the resulting permission changes within the configured SLA (default ≤5 minutes) and marks the task Completed with change results. - Given campaign application mode is Queue for Admin Review, When a reviewer submits Revoke/Modify decisions, Then a change request is created with status Pending Admin and no permissions are altered until an admin approves. - Given an admin approves a queued change, When the change is applied, Then the subject’s permissions reflect the decision and the task is marked Completed with an auditable link to the change record. - Given a change application fails, When retries are exhausted (e.g., 3 attempts), Then the task is set to Exception, the reviewer and admin are notified, and a retry/rollback option is available. - Given Approve decisions, When application mode is either setting, Then no permission changes are performed and the approval is recorded only.
Real-Time Campaign Progress and Export
- Given an active campaign, When the progress view loads, Then it displays totals for subjects, completed, pending, overdue, completion percentage, and trend, and refreshes at least every 60 seconds without a full page reload. - Given filters (campaign, reviewer, department, matter, role, status), When multiple filters are applied, Then results update within 2 seconds and counts reflect filtered data accurately. - Given a user clicks into a metric, When drilling down, Then a list of matching tasks is shown with sortable columns and links to each task. - Given the Export action, When CSV and PDF exports are generated, Then they contain the current filtered dataset, are time-stamped, and match on-screen totals. - Given permissions, When a non-admin views the dashboard, Then they only see campaigns and tasks they are authorized to view.
Evidence Capture and Audit Readiness
- Given any decision is made, When the system records evidence, Then it stores an immutable bundle including reviewer ID, subject ID, roles reviewed, action, rationale, timestamps, IP/device, before/after role sets, and assignment source. - Given a campaign completes or on-demand, When an audit report is generated, Then the system produces a downloadable package (CSV of decisions + PDF summary per reviewer) with cryptographic checksums for integrity. - Given retention policy (e.g., 7 years), When the retention window is configured, Then evidence is retained for the specified duration, and edits are prohibited; corrections create append-only entries linked to originals. - Given external auditors, When read-only access is granted, Then they can view evidence and reports without ability to alter data, and access is logged. - Given API access, When retrieving evidence via API, Then responses include pagination, filtering, and checksum values identical to UI exports.
Auto-Revocation on Non-Response
- Given auto-revocation is enabled with a grace period (e.g., 7 days after due), When a task remains incomplete past the grace period, Then the system auto-revokes only roles marked as stale and eligible for auto-revocation and applies changes automatically. - Given pending auto-revocation, When 24 hours remain in the grace period, Then a final warning is sent to the reviewer and subject with the list of roles at risk. - Given exclusion rules/whitelists, When auto-revocation runs, Then exempt roles and users are not altered and are reported as skipped with reasons. - Given an auto-revocation is executed, When it completes, Then the action is logged with rationale "Non-response auto-revocation," notifications are sent to the subject and their manager, and a one-click rollback is available for 14 days. - Given an auto-revocation attempt fails, When retried up to the configured limit, Then the task moves to Exception state with alerts to admins and remediation guidance.
Drift Alerts & Weekly Digest
"As a security-conscious partner, I want concise alerts and a weekly digest so that I stay informed and can act quickly without being overwhelmed."
Description

Deliver real-time drift alerts via in-app notifications, email, and Slack/Microsoft Teams, with rate limiting, suppression of repeated alerts, and grouping by role or scope. Include actionable links to view diffs, accept as new baseline, or trigger rollback. Provide a weekly digest summarizing changes, risk levels, outstanding attestations, and exceptions to keep leadership informed without alert fatigue.

Acceptance Criteria
Real-Time Drift Alert Delivery Across Channels
Given a baseline role template exists and drift monitoring is enabled And a permission change creates drift with risk score >= Medium When Drift Guard detects the drift Then an in-app notification is created within 5 seconds of detection And an email notification is sent to subscribed recipients within 60 seconds And a Slack or Microsoft Teams message is posted to the configured destination within 15 seconds And the alert payload includes role name, affected scope(s), changed permissions summary, risk level, ISO 8601 timestamp, environment, and a unique alert ID And recipients’ channel preferences and do-not-disturb windows are honored And delivery failures are retried up to 3 times with exponential backoff and recorded in audit logs
Alert Rate Limiting and De-duplication
Given alert rate limiting is enabled with default settings When multiple identical drift signatures occur for the same role-scope within a 15-minute window Then only one alert per channel is sent and subsequent alerts are suppressed during that window And suppressed alert counts are aggregated and visible in the alert detail view And if the drift’s risk level escalates during the window, a new alert is sent immediately And no user receives more than 10 drift alerts per 24 hours across all channels And suppression resets when the drift is resolved, rolled back, or accepted as new baseline And suppressed alert totals are included in the weekly digest
Alert Grouping by Role and Scope
Given multiple distinct permission changes are detected for the same role or scope within a 5-minute grouping window When alerts are generated Then a single grouped alert is sent summarizing all changes detected (up to 20 items per group) And the alert lists the top 5 highest-risk changes with risk labels and provides a “View all” link to the complete set And grouped alerts preserve per-change traceability in the diff view And if more than 20 changes occur, additional grouped alerts are created with sequence numbers And grouping never merges items from different environments or tenants
Actionable Links in Alerts (Diff, Accept Baseline, Rollback)
Given a recipient receives a drift alert When the recipient clicks “View diff” Then the diff page loads within 2 seconds and displays before/after permission sets with highlighted changes When the recipient clicks “Accept as new baseline” Then a confirmation prompt appears; upon confirmation the baseline updates, the alert is closed, and a confirmation message is issued When the recipient clicks “Trigger rollback” Then authorization is validated, 2FA is enforced if enabled, the rollback completes within 60 seconds, and success/failure is reported to the initiator And all actionable links are single-use, CSRF-protected, cryptographically signed, and expire after 24 hours And all actions are idempotent and fully audit logged (actor, time, objects, outcome)
Weekly Digest Summary and Delivery
Given leadership recipients and digest destinations are configured And at least one drift event occurred in the last 7 days When the weekly digest job runs each Monday at 08:00 firm local time Then a digest is generated covering the prior 7 days including: total drifts, counts by risk level, top changed roles, outstanding attestations, active exceptions, and suppressed alert totals And the digest is delivered via email and posted to the configured Slack/Teams channel within 5 minutes of generation And the same digest is accessible in-app with identical metrics and content And recipient subscription preferences are honored; unsubscribed recipients do not receive the digest And all counts and time ranges in the digest match in-app reporting within 1%
Attestation Reminders and Exceptions Handling
Given roles marked as “Requires Attestation” and assigned owners When an attestation is due within 7 days or is overdue Then the weekly digest lists each item with owner, due date, risk, and an “Attest now” action And selecting “Attest now” opens an attestation panel to approve/reject with comment and updates status immediately upon submission And exceptions can be recorded with justification and expiry date; items remain visible until expired or revoked And overdue attestations older than 14 days are escalated to the designated leader via high-priority Slack/Teams and email And all attestation and exception actions are audit logged and included in compliance reports
Immutable Audit Log & Evidence Export
"As a compliance manager, I want tamper-evident audit trails and exportable evidence so that I can satisfy audits and client due diligence efficiently."
Description

Maintain an immutable timeline of drift detections, approvals, rollbacks, and attestations with actor, timestamp, rationale, and before/after permission diffs. Support exportable evidence packages (PDF/CSV/JSON) for client security questionnaires and regulator audits, configurable retention policies, and a queryable API for SIEM/SOC integrations.

Acceptance Criteria
Immutability & Hash-Chained Audit Records
Given any event of type DRIFT_DETECTED, APPROVAL_GRANTED, ROLLBACK_EXECUTED, or ATTESTATION_COMPLETED is committed When the record is persisted Then the record contains recordId (UUIDv4), previousRecordHash, recordHash (SHA-256), createdAt (UTC ISO-8601 with ms), actorId, actorType (user|service), eventType, sourceIp, and requestId And updates or deletes of existing records via API return 405 Method Not Allowed And updates or deletes at the data store are technically blocked (WORM/ACL) and a TAMPER_ATTEMPT event is appended with actor identity and failure reason And GET /api/v1/audit/verify?from=...&to=... validates the hash chain and returns 200 with chainValid=true when all records in range verify, or 409 with chainValid=false and firstInvalidRecordId when any link fails
Permission Diff Accuracy for Drift/Approval/Rollback
Given a drift is detected by comparing current role vs its baseline template When the DRIFT_DETECTED event is logged Then the payload includes beforePermissions and afterPermissions as canonicalized JSON arrays and a diff object with added[], removed[], and changed[] entries whose counts equal the net change And when a rollback is executed, the ROLLBACK_EXECUTED event's beforePermissions equals the state immediately pre-rollback and afterPermissions equals the restored baseline, and the diff is the inverse of the corresponding drift diff And when an approval is granted or rejected, the APPROVAL_GRANTED/APPROVAL_REJECTED event references the originating drift eventId and includes non-empty rationale text (min 10 characters) or a policyId for auto-approval
Evidence Package Export (PDF/CSV/JSON) with Manifests
Given a user with role AuditExporter selects a date range, event types, and export mode When an export is requested Then the system produces a package containing report.pdf, events.csv, events.json, and manifest.json with per-file SHA-256 checksums, generatedAt (UTC), requesterId, and applied filters And downloads verify each file's checksum matches the manifest; otherwise the download is blocked with 422 Unprocessable Entity And exporting up to 500,000 events completes within 15 minutes at the 95th percentile, processed asynchronously with status available at GET /api/v1/exports/{id} And PDF includes cover details (firm, environment, time window, event count) and renders actor, rationale, and before/after diffs per event
Configurable Retention and Legal Hold
Given an OrgAdmin sets an audit retention period (e.g., 90, 180, 365 days) and optional legal hold rules When the policy is saved Then future purge jobs run daily at 02:00 UTC and mark only records older than the retention period and not under legal hold as purge-eligible And when a purge executes, a PURGE_SUMMARY event is appended with purgedCount, cutoffDate, and policyVersion, and a list of purged recordIds is stored in cold storage for 90 days And changing retention or hold settings is itself recorded as a CONFIG_CHANGE event with actor, timestamp, oldValue, and newValue And records under legal hold are never purged until the hold is lifted, regardless of age
Queryable Audit API for SIEM/SOC
Given a SIEM client authenticates with an API key scoped audit:read When it calls GET /api/v1/audit?from&to&eventType&actorId&cursor&limit Then results are returned in chronological order with cursor-based pagination, default limit=1000 and max=5000, and each page includes next and prev cursors And conditional requests with If-None-Match ETag return 304 when no new data since the last response And GET /api/v1/audit/stream provides server-sent events delivering new records within 2 seconds of commit And rate limiting enforces 600 requests per minute per key with 429 responses and Retry-After header on exceed
Access Control, Redaction, and Expiry for Exports
Given a user attempts to create or download an export When the user lacks AuditExporter or OrgAdmin role Then the request is denied with 403 and an ACCESS_DENIED event is logged with actor and attempted action And when "Client-Safe" mode is selected, PII fields (email, phone, streetAddress) are masked consistently across PDF/CSV/JSON; when "Full" mode is selected, no masking is applied And export download URLs are single-use signed links that expire in 15 minutes; packages expire and are deleted after 7 days with a PACKAGE_EXPIRED event recorded
Scheduled Attestations Logged with Evidence
Given monthly attestations are configured for role templates When an attestor completes an attestation Then an ATTESTATION_COMPLETED event is recorded with attestorId, roleId, attestPeriod (start/end), attestedPermissions snapshot, outcome (approved|changes_required), and optional rationale, plus references to related drift eventIds within the period And when the attestation due date passes without completion, an ATTESTATION_MISSED event is appended with assignee and dueDate And when a one-click rollback is initiated from an attestation, a ROLLBACK_EXECUTED event is chained to the attestation via parentEventId and includes before/after and diff consistent with the applied change

Entity Stitcher

Automatically resolves duplicate individuals into a single, clean graph node by unifying aliases, emails, phones, addresses, and prior matters with confidence scoring and source lineage. Reduces manual dedupe, prevents missed conflicts from fragmented records, and updates in sub‑second time as new details arrive.

Requirements

Sub-second Entity Resolution
"As a solo attorney, I want duplicate client records to resolve instantly as new details arrive so that conflicts are accurate and I can move from call to filing without manual cleanup."
Description

Implements a real-time merge engine that deduplicates individuals into a single canonical node within p95 < 500 ms of any new or updated intake data, call transcription, e-sign event, or docket import. The service ingests incremental updates, computes match candidates, and applies idempotent upserts to maintain a consistent person graph. It horizontally scales to handle bursty intake traffic, provides exactly-once merge semantics via merge keys, and guarantees atomic attribute consolidation to prevent partial merges. Integrated with CaseSpark’s intake and conflict screening pipelines, it emits change events so downstream modules (conflict checks, document assembly) react immediately to a newly unified entity. The outcome is a continuously clean entity layer that prevents fragmented records and missed conflicts without adding manual steps.

Acceptance Criteria
Sub-Second Merge on New Intake Update
Given a new or updated person attribute arrives via intake, call transcription, e-sign, or docket import When the update is accepted by the merge engine Then the canonical person node is created or updated and persisted within 500 ms at p95 measured over 10,000 events under bursting load And a change event is published for the affected entity within the same 500 ms budget And p99 end-to-end latency is <= 900 ms with error rate <= 0.1% during the test window
Exactly-Once Merge via Merge Keys
Given an update payload with mergeKey K is delivered three times, including out-of-order duplicates across workers When the engine processes these deliveries Then only one merge/upsert is applied and the canonical node version increments exactly once And no duplicate attributes or edges are created in the graph And only one change event with a stable eventId is emitted; duplicates are deduplicated downstream
Atomic Attribute Consolidation
Given a merge operation that consolidates multiple attributes and relationships into a canonical node And a simulated failure occurs mid-operation (e.g., crash between attribute and edge writes) When the system recovers and retries Then either all intended changes are committed or none are visible (no partial state) And the retry completes without manual intervention and without data loss And the audit log shows a single committed transaction for the merge
Horizontal Scaling Under Bursty Intake
Given intake traffic bursts to 1,000 updates/second for 5 minutes with 10x variance When autoscaling is enabled with min=2 and max=30 workers Then the system maintains p95 merge latency < 500 ms throughout the burst And stabilizes within 90 seconds of burst start without scaling thrash (>3 scale actions per minute) And backlog queue depth returns to <100 events within 60 seconds after the burst ends
Concurrent Updates to the Same Person
Given two distinct updates for the same individual (e.g., phone and address) arrive concurrently on different partitions When processed by the merge engine with optimistic concurrency Then exactly one canonical node exists post-merge And both updates are reflected without lost updates or overwrite anomalies And no deadlocks occur and retries do not exceed three attempts
Immediate Downstream Reaction to Merge Events
Given a merge unifies two previously separate person records When the change event is published by the merge engine Then the conflict screening pipeline consumes and processes the event within 300 ms And conflicts for open matters involving the person are recalculated within 1 second from event publish And document assembly caches referencing the person are invalidated within 1 second from event publish
Confidence Scoring & Threshold Controls
"As an intake paralegal, I want clear confidence scores with adjustable thresholds so that I can safely auto-merge obvious duplicates and review edge cases efficiently."
Description

Provides an explainable scoring model that weights evidence across identifiers (emails, phones, addresses, names, DOB) and historical matter associations to determine match confidence. Exposes configurable thresholds for auto-merge, needs-review, and no-merge, with tenant-level defaults and per-workflow overrides. Each decision includes a rationale summary (e.g., shared primary email + DOB match) to aid auditability and user trust. Integrates with the review queue for borderline cases and with the merge engine for autonomous merges above threshold. Ensures safe dedupe while minimizing false positives that could contaminate conflict checks.

Acceptance Criteria
Autonomous Merge When Score Exceeds Threshold
Given tenant-level default thresholds and optional per-workflow overrides are configured And a candidate pair of person records has a computed confidence score S When S is greater than or equal to the effective auto-merge threshold T_auto for the active workflow Then the system invokes the merge engine to merge the pair into a single graph node without user intervention And the merged node contains the union of identifiers (aliases, emails, phones, addresses) and prior matters, each with preserved source lineage And a human-readable rationale summary (e.g., shared primary email + DOB match) and machine-readable evidence list are attached to the decision record And an event entity.merged with decision_id, score S, thresholds_used, and entity_ids is published to the event bus And the merge operation is idempotent: reprocessing the same pair within 24 hours does not create duplicate merges or duplicate events And precision at the auto-merge threshold is at least 99.5% on the maintained benchmark suite before enabling auto-merge in production for a tenant
Borderline Scores Routed to Review Queue
Given the needs-review score range [T_review_min, T_review_max) is configured for the tenant/workflow And a candidate pair has a score S within [T_review_min, T_review_max) When scoring completes Then no merge is performed automatically And a review queue item is created containing candidate_entity_ids, score S, thresholds_used, rationale_summary, and top_evidence with weights and sources And the review item is assigned according to the workflow’s routing rules and appears in the queue within 2 seconds of scoring completion And user actions of Approve Merge or Reject are captured with user_id, timestamp, and comment And upon Approve Merge, the merge engine is invoked and the review item status updates to Resolved: Merged And upon Reject, no merge occurs and a suppression record is stored to prevent re-queuing the same pair for 30 days unless S increases by at least Δ=0.1 from new evidence
Low Confidence Leads to No-Merge
Given a no-merge threshold T_no_merge is configured such that T_no_merge < T_review_min < T_auto And a candidate pair has a score S < T_no_merge When scoring completes Then no merge is performed and no review item is created And a decision record with type No-Merge is persisted with score S, thresholds_used, and rationale indicating insufficient evidence And a suppression record prevents the same pair from being considered again for 7 days unless new attributes change S by at least Δ=0.2 And the API reports decision_type=NO_MERGE when queried for the pair within the suppression period
Explainable Rationale Included with Every Decision
Given a decision is produced (Auto-Merge, Needs-Review, or No-Merge) When the decision record is created Then a rationale_summary field is included with a concise human-readable explanation referencing the strongest evidence (e.g., primary email match + DOB exact match) And an evidence array is included enumerating each feature used (name variant score, email match, phone match, address proximity, DOB match, matter co-participation), with weight, contribution to score, and source_ids And both rationale_summary and evidence are returned by the decisions API and displayed in the review UI without truncation for summaries up to 300 characters And sensitive fields not permitted by the viewer’s role are redacted per the tenant’s data access policy while preserving the explanation structure
Tenant Defaults and Per-Workflow Threshold Overrides
Given tenant-level default thresholds (T_auto, T_review_min, T_review_max, T_no_merge) are set And a workflow-specific override is optionally configured When a scoring decision is made within a workflow Then the effective thresholds for that workflow are applied; otherwise the tenant defaults are used And thresholds must satisfy 0 ≤ T_no_merge < T_review_min < T_review_max < T_auto ≤ 1; invalid configurations are rejected with a validation error And changes to thresholds take effect for new decisions within 60 seconds and are versioned with changed_by, timestamp, and previous_values in an audit trail And only users with Threshold:Manage permission can create or update thresholds; unauthorized attempts are denied and logged
Real-Time Scoring Latency and Determinism
Given a new identifier (e.g., email, phone, address, alias, DOB) or matter association is ingested for an entity When the scoring pipeline evaluates potential matches Then the resulting decision (Auto-Merge, Needs-Review, or No-Merge) is persisted within 750 ms at p95 and 1500 ms at p99 from ingestion to decision availability And given identical inputs and model weights, the computed confidence score is deterministic across runs and deployments And concurrent updates on the same entities produce a single consistent decision via optimistic locking or equivalent, with no lost updates or duplicate merges
Decision Audit Log and Source Lineage
Given any deduplication decision is made When the system records the decision Then an immutable audit log entry is created containing: decision_id, timestamp, tenant_id, workflow_id, candidate_entity_ids, decision_type, score, thresholds_used, rationale_summary, evidence (features with weights and source_ids), actor (system or user), and review_item_id if applicable And audit entries are queryable by date range, entity_id, decision_type, and workflow_id via API with pagination And audit entries are retained for at least 7 years (configurable per tenant) and are exportable as NDJSON or CSV And a daily integrity check validates log completeness; any discrepancies raise an alert within 5 minutes
Source Lineage & Provenance Ledger
"As a managing attorney, I want full source lineage for merged client data so that I can audit decisions and demonstrate compliance if a record is questioned."
Description

Captures and preserves source lineage for every attribute on an entity node, including origin system (intake form, call log, e-sign packet, docket pull), timestamp, collector, and transformation steps. Maintains a tamper-evident ledger of merges and splits with before/after snapshots to support audits, compliance, and reversibility. Surfaces provenance in the UI so users can see where an alias, address, or phone originated and why it was retained or superseded. Enables exportable audit reports and assists regulatory responses without degrading performance of the real-time merge path.

Acceptance Criteria
Attribute Lineage Capture on Inbound Intake Form
Given an attorney submits a new client intake with alias, email, phone, and address When the Entity Stitcher persists the entity Then each attribute value is stored with lineage fields: origin_system, event_timestamp (ISO-8601 UTC), collector_id, transformation_steps[], and source_record_id Given multiple sources contribute the same attribute value within 10 minutes When the entity is saved Then all distinct lineages are retained and associated to the single normalized value with per-source confidence scores Given a saved attribute When queried via lineage API by entity_id and attribute key Then the response returns all lineage records within 200 ms for up to 50 records Given a saved attribute When a write occurs Then the lineage record is immutable and updates require appending a superseding lineage entry (attempted direct update returns 409)
Tamper‑Evident Merge Ledger with Before/After Snapshots
Given a merge of two person nodes occurs When the operation completes Then an append-only ledger entry is written with fields: event_type (merge), actor_id, rule_id, confidence, before_snapshot_id, after_snapshot_id, affected_attribute_keys[], created_at Given a new ledger entry is written When the ledger is read Then it contains a SHA-256 hash of the entry payload and a prev_hash referencing the prior entry for that entity, forming a verifiable chain Given any byte of a stored ledger entry is altered When the verification job runs Then the chain verification fails, the entity is flagged with integrity_status=invalid, and an audit alert is emitted Given a merge or split occurs When the ledger write executes Then it completes within 100 ms P95 and does not block the real-time merge commit
Provenance Visibility in Entity UI Panels
Given a user views an entity's alias, email, phone, or address card When they open the “Provenance” panel Then the UI displays for the selected value: origin_system, first_seen_at, last_seen_at, collector_id, transformation_steps[], and retention_reason (rule or user action) Given a value was superseded by a newer source When the user opens the provenance panel Then the UI labels the value as superseded and shows superseding source, event timestamp, and rule_id explanation Given typical network conditions When the provenance panel is requested Then it renders within 300 ms P95 for entities with up to 100 lineage records Given the user lacks audit permissions When they attempt to open provenance Then the panel is blocked with a 403 and the access attempt is logged
Exportable Audit Report for Regulatory Response
Given an authorized auditor selects an entity and date range When they request an audit export Then the system produces downloadable CSV and PDF containing ledger events, lineage details per attribute, and before/after snapshot references Given an export is generated When the files are downloaded Then each file includes a SHA-256 checksum and metadata: entity_id, report_range, generated_at, requester_id Given an entity with up to 10,000 ledger events When an export is requested Then the export completes within 30 seconds P95 with pagination for CSV and a table of contents for PDF Given PII redaction is enabled When the export is generated Then emails and phones are masked (e.g., last 4 visible) and full values appear only when redaction is disabled
Reversible Merge/Split with Targeted Rollback
Given a prior merge of entities A and B exists in the ledger When an authorized user requests rollback to the pre-merge snapshot Then the system restores the before_snapshot as the current state and records a rollback event linked to the original merge Given a rollback completes When lineage and ledger are queried Then all superseded attribute values and associations are reinstated and the hash chain remains valid via a new entry referencing prev_hash Given downstream indexes (search and conflict screening) exist When a rollback completes Then they reflect the restored graph within 5 seconds and no dangling references remain Given a rollback is requested for a non-reversible event When the request is made Then the system rejects it with 422 and guidance on required prerequisites
Real‑Time Merge Path Performance Under Load
Given a steady load of 50 attribute updates/sec and 10 merges/sec for 15 minutes When the system processes events Then end-to-end merge latency is ≤ 500 ms P95 and ≤ 1,000 ms P99 from intake to entity commit Given ledger and lineage writes occur during the same load When performance is measured Then audit-path write latency is ≤ 100 ms P95 and adds ≤ 5% overhead to merge latency versus audit-disabled baseline Given a burst of 5× the steady load for 60 seconds When backpressure engages Then merges succeed with no data loss and audit writes queue and drain within 2 minutes with FIFO order preserved
Alias & Attribute Normalization Pipeline
"As a conflicts analyst, I want consistent normalization of contact details so that the system can detect duplicates even when data is entered in different formats."
Description

Normalizes names, emails, phones, and addresses prior to matching to improve precision and recall. Applies locale-aware transformations (e.g., Unicode and punctuation handling), email canonicalization (lowercasing, plus-tag removal), E.164 phone standardization, and postal address normalization with jurisdiction-aware validation. Includes phonetic encodings and common nickname mappings to capture alias variants without over-merging. Operates as a stateless, reusable service invoked by intake, import, and merge workflows, ensuring consistent inputs for scoring and downstream document assembly.

Acceptance Criteria
Normalize Person Names with Locale-Aware Rules
- Given a raw person name containing mixed case, diacritics, punctuation, honorifics, and legal suffixes (e.g., "JOSÉ M. O’CONNOR JR."), When the normalization service is invoked with locale="en-US", Then the response includes: canonical_name="jose oconnor", middle_name_initial="m", suffix="jr", display_name preserved with proper casing rules, and a stable normalization_key. - Given locale-specific diacritic folding and punctuation rules, When the same name is processed with locale="es-ES", Then diacritics are preserved in display_name but removed in match_key per locale tables, and apostrophes/hyphens are normalized according to the locale configuration. - Given irregular whitespace or leading/trailing spaces, When processed, Then whitespace is trimmed and collapsed to single spaces in all normalized outputs. - Given identical inputs across multiple calls, When processed, Then outputs are deterministic and identical (idempotent) including normalization_key.
Email Canonicalization with Plus-Tag Removal
- Given an email address with uppercase characters and a plus tag in the local-part (e.g., "User+intake@bücher.de"), When normalized, Then the canonical_email is "user@xn--bcher-kva.de" (local and domain lowercased, plus-tag removed, domain IDNA-normalized), and display_email preserves the Unicode domain. - Given an email without a plus tag, When normalized, Then canonical_email lowercases the local and domain parts and preserves dots and hyphens (no dot-collapsing), and the normalization_key is stable across calls. - Given an invalid email (fails RFC syntax), When processed, Then the service returns validity=false with error_code="EMAIL_INVALID_SYNTAX" and does not emit a canonical_email. - Given the same email from different workflows (intake, import, merge), When normalized, Then canonical_email and normalization_key are identical across workflows.
Phone Number Standardization to E.164
- Given a national-format phone and a jurisdiction context (e.g., "(415) 555-1212", jurisdiction="US"), When normalized, Then e164="+14155551212", country="US", and extension is null. - Given a number containing an explicit country code and an extension (e.g., "+44 20 7946 0958 x123"), When normalized, Then e164="+442079460958", country="GB", ext="123". - Given an input that cannot form a valid number for the inferred or provided country, When processed, Then validity=false with error_code="PHONE_INVALID" and no e164 is emitted. - Given repeated invocations with identical input and context, When processed, Then the e164 and normalization_key are identical (idempotent).
Postal Address Normalization with Jurisdiction Validation
- Given a US address with mixed formatting (e.g., "123 Main St., Apt 4B, Springfield, IL 62704"), When normalized with jurisdiction="US", Then the response includes standardized components: street_number=123, street_name="Main", street_type="St", unit_type="Apt", unit="4B", city="Springfield", region="IL", postal_code="62704", country="US", plus a normalized_line1 and normalized_line2, and validity=true. - Given a GB address (e.g., "10 Downing Street, London SW1A 2AA"), When normalized with jurisdiction="GB", Then region/county and postcode formats are validated, casing normalized, and normalized_line fields produced per GB conventions. - Given an address with an invalid postal code for the jurisdiction, When processed, Then validity=false with error_code="ADDRESS_POSTAL_INVALID" and normalized components still returned where derivable. - Given no jurisdiction, When processed, Then locale-agnostic normalization (trimming, token order where inferable) is applied and validity is set to unknown.
Phonetic Encodings and Nickname Mapping Without Over-Merging
- Given a name "William Thompson" and locale="en-US", When normalized, Then phonetic encodings are produced for given and family names and alias_variants includes "Bill Thompson" and "Will Thompson" sourced from the locale-specific nickname map. - Given a name "Guillermo Ortega" and locale="es-MX", When normalized, Then alias_variants may include "Memo Ortega" per the locale nickname map; when locale="en-US" for the same input, Then no "Memo" alias is emitted. - Given a name "Willow Parker", When normalized, Then no alias variant "Will Parker" is emitted because it is not present in the curated nickname map (preventing over-merging). - Given configured maximum alias variants per name (e.g., 5), When normalization would exceed the cap, Then the service truncates to the cap and records which variants were dropped in reasons.
Stateless Reusable Service Across Workflows with Performance Targets
- Given the service is invoked by intake, import, and merge workflows, When each submits the same payload, Then the normalized outputs (canonical values, keys, validity flags) are identical across workflows. - Given sequential and concurrent requests, When the same input is sent 3 times from different clients, Then the outputs are identical and no server-side state affects results (stateless behavior). - Given single-record requests under normal load, When measured over 1,000 requests, Then p95 latency per record is <= 150 ms and p99 <= 300 ms. - Given batch requests of 100 records, When measured over 100 batches, Then p95 total batch latency is <= 3,000 ms and no per-record accuracy deviations are observed compared to single-record mode.
Transformation Audit Trail and Configuration Versioning
- Given any normalized field (name, email, phone, address), When processed, Then the response includes an audit object per field with: original_value, normalized_value, locale/jurisdiction used, ruleset_version, and transformations_applied (ordered list of steps). - Given a change in normalization configuration (ruleset_version increment), When the same input is processed before and after the change, Then normalization_key changes only if a rule affecting that field changed, and the audit object reflects the new ruleset_version. - Given downstream systems request provenance, When they read the audit object, Then they can reconstruct which transformations were applied without accessing server state (all details returned in the response).
Merge Review Queue with One-click Undo
"As an office administrator, I want a review queue with easy approve/deny and undo so that I can control risky merges while keeping intake moving."
Description

Delivers a human-in-the-loop review experience for borderline matches, presenting side-by-side attribute comparisons, confidence rationale, and quick actions to approve, reject, or defer. Supports role-based access, bulk actions, and searchable filters by matter, score band, or data source. Every approved merge is instantly reversible via one-click undo that restores prior nodes and attributes using the provenance ledger. Notifications and activity logs keep teams informed of pending reviews and decisions, ensuring quality without slowing intake throughput.

Acceptance Criteria
Approve Borderline Match with Comparison and Rationale
Given a queue item with a confidence score within the configurable “borderline” band (default 0.60–0.79) When a reviewer opens the item Then the UI renders within 500 ms (p95) a side-by-side comparison showing all differing attributes (names, aliases, emails, phones, addresses, prior matters) And each attribute displays source lineage (source system, record ID, timestamp) with at least one source tag per attribute And the confidence rationale shows the overall score and the top 5 contributing signals with weights When the reviewer clicks Approve Merge Then a single merged node is created per stitch rules, the original node IDs are recorded in the provenance ledger, and the queue item is removed And the entity profile reflects merged attributes within 1 second (p95) And an activity log entry is created with actor, action, item IDs, before/after attribute summary, score, and sources And subscribed users receive an in-app notification within 10 seconds
Reject Borderline Match Keeps Records Separate
Given a queue item within the borderline score band When a reviewer clicks Reject Then no merge operation executes and both records remain separate with no attribute changes And the item is removed from the review queue And the same candidate pair is suppressed from re-suggestion for 30 days or until the confidence score increases by ≥0.10 (whichever occurs first) And an activity log entry records actor, action, item IDs, score at decision, and rationale (free-text optional) And the action completes and the queue updates within 800 ms (p95)
Defer Decision with Reason and SLA Reminders
Given a queue item within the borderline score band When a reviewer selects Defer and chooses a reason from a required list and sets a due date (default +24 hours) Then the item is marked Deferred with visible reason and due date badges And the item is removed from the active list and appears in the Deferred tab and in the reviewer’s Pending list And an in-app reminder is delivered 60 minutes before due and at due time (email if user has email alerts enabled), delivered within ±1 minute And if the item remains deferred past due by 24 hours, it escalates to the team lead notification channel And the defer action, reason, and due date are recorded in the activity log And resuming the item returns it to the top of the queue and clears reminders
One-Click Undo Restores Prior State from Provenance Ledger
Given a merge that was previously approved via the review queue When a user with permissions clicks Undo on the merge activity entry or the merged entity profile Then the system restores the exact pre-merge state: resurrects prior node IDs, attributes, relationships, and assignments as recorded in the provenance ledger And the merged node is archived with a reversal marker and linkage to prior node IDs And all affected indexes and search results reflect the undo within 1 second in UI (p95) and within 5 seconds in background search APIs (p95) And the undo operation is idempotent; a second undo request on the same merge is rejected with a clear message and no state change And an activity log entry captures actor, action=Undo, original merge ID, timestamps, and affected node IDs And subscribed users receive an in-app notification within 10 seconds
Role-Based Access Controls for Review Actions
Given role definitions: Reviewer (approve/reject/defer), Admin (all actions + settings), Viewer (read-only) When a Viewer opens the review queue Then action controls (Approve/Reject/Defer/Bulk/Undo) are disabled and API calls to perform actions return 403 When a Reviewer performs Approve/Reject/Defer Then the action succeeds and is attributed to the reviewer in the activity log When a non-Admin attempts to change queue settings or perform bulk actions over the configured threshold Then the request is blocked with 403 and a UI message explains the required role And all access denials are recorded in the security audit log with user ID, role, endpoint, and timestamp
Bulk Actions and Safeguards on Multiple Matches
Given a user selects between 2 and 100 queue items When the user initiates Bulk Approve or Bulk Reject Then a confirmation dialog shows the total count, score band distribution, and a preview of the first 3 items And after confirmation, items are processed individually with progress feedback and no more than 5 concurrent operations And the system produces a completion summary listing successes and failures with reasons And partial failures do not roll back successful items And per-item activity log entries are created; a bulk batch ID links them And processing 100 approves completes within 15 seconds (p95) under a 10k-item queue And a bulk undo option is available from the summary to undo all or selected successful items
Search and Filter Review Queue by Matter, Score Band, and Data Source
Given a review queue with items across multiple matters, score bands, and data sources When a user applies filters for Matter, Score Band, Data Source, Assigned Reviewer, and Date Range Then results update using AND logic and display a count of matches And free-text search across party name, alias, email, and phone returns matching items with highlights And sorting by Score (desc), Date Added (desc), and Matter (asc) is available And results render within 500 ms (p95) for up to 10,000 items And the current filter and sort state persists in the URL and is restored on reload and across sessions for 7 days
Conflict Graph Auto-Refresh on Merge/Split
"As a practitioner, I want conflicts to update immediately after a dedupe or undo so that I can make engagement decisions with current, accurate information."
Description

Automatically recomputes and propagates conflict relationships whenever entities are merged or split, updating matter-party links and screening outcomes in near real time. Emits structured events to the conflict screening service and updates open intake sessions, highlighting any newly detected conflicts or clearing false positives caused by duplicates. Ensures transactional consistency between the entity graph and the conflict engine, with retry-safe processing and observability metrics to validate refresh timeliness and correctness.

Acceptance Criteria
Merge refresh: recompute conflicts, update matter links, and notify services
Given two person nodes A and B exist with distinct identifiers and matter links (M1, M2) And open intake session S is screening a party related to A or B When Entity Stitcher merges A and B into winner W with loser L Then within 1s p95 the graph shows W with unified aliases/emails/phones/addresses and prior matters of A and B And all matter-party links formerly pointing to L are atomically re-pointed to W And a MergeCommitted event with idempotency_key and change_version is emitted to the conflict screening service within 500ms p95 And within 2s p95 the conflict engine recomputes conflict relationships for W and affected matters And open intake session S reflects updated screening outcomes, highlighting any newly detected conflicts And an audit log entry with correlation_id ties the merge to the refresh outcomes
Split refresh: clear false positives and recompute screening
Given person node W was previously merged and is linked to matters Mx And a false-positive conflict exists due to the prior merge When W is split into W1 and W2 with an explicit reassignment map for matter-party links Then within 1s p95 graph state shows W1/W2 with correct partitioned attributes and links And a SplitCommitted event with idempotency_key and change_version is emitted within 500ms p95 And within 2s p95 the conflict engine recomputes conflicts and clears false positives introduced by the prior merge And open intake sessions related to Mx receive an update that removes cleared conflicts and annotations And audit logs capture the split, reassignment map, and downstream refresh results
Structured event emission with lineage and idempotency
Given a merge or split has been committed in the entity graph When emitting to the conflict screening service Then each event conforms to the schema: {event_type in ["merge_committed","split_committed"], entity_ids, affected_matter_ids, change_version (monotonic per entity), occurred_at (UTC ISO8601), idempotency_key (UUIDv4), correlation_id, lineage_sources} And events are delivered at-least-once and ordered by change_version per entity And consumers can deduplicate using idempotency_key with no loss of correctness And malformed or incomplete events are rejected, logged with correlation_id, and do not advance change_version
Transactional consistency between graph and conflict engine
Given a merge or split transaction is executing When reads occur against the entity graph and conflict screening results during the refresh window Then clients observe either pre-change or post-change states consistently for a given change_version, never a mixed state And the conflict engine only processes events after the graph transaction commits and includes the committed change_version And stale reads beyond 2s p95 after commit are prevented; all services converge to the committed version within 5s p99 And no matter-party link points to a deleted/loser node at any time after commit
Retry-safe and idempotent processing
Given the conflict screening service or message bus experiences intermittent failures When the same MergeCommitted or SplitCommitted event is retried and processed multiple times Then the final graph-to-conflict state is correct with no duplicate conflict entries or duplicate matter-party link updates And processing uses idempotency_key and change_version to ensure exactly-once effects per entity version And after N=10 failed delivery attempts the event is moved to a DLQ with alerting and retained for replay And replaying DLQ events results in the same correct final state
Observability, SLOs, and alerts for refresh timeliness and correctness
Given routine merges and splits occur under typical load When measuring system behavior Then metrics exist and are tagged by tenant and change_version: refresh_latency_ms (graph->engine->UI), queue_lag_seconds, event_error_rate, idempotency_dedup_count, recompute_count, stale_read_count And SLOs hold over a rolling 7 days: refresh_latency_ms p95 <= 2000, p99 <= 5000; event_error_rate <= 0.1%; stale_read_count == 0 for p95 window And dashboards visualize latency distributions and correctness counters; alerts fire within 2 minutes on SLO breach And distributed traces correlate graph write, event emission, conflict recompute, and UI push via correlation_id
Open intake session highlights for new or cleared conflicts
Given an intake session is open for Matter M and screening candidate C When a merge or split affecting C changes conflict status Then within 2s p95 the intake client receives a push update (WebSocket/SSE) indicating new or cleared conflicts And newly detected conflicts render with highlight and a reason sourced from lineage data; cleared conflicts remove prior highlights/banners And the session timeline logs an immutable entry with before/after conflict counts, correlation_id, and timestamp And the user can proceed without manual refresh, and no stale conflict banners persist after clearance

Relationship Lens

Surfaces indirect conflicts by mapping non‑obvious ties like households, co‑parents, employers, referrers, shared addresses, and emergency contacts. Weights ties by recency and interaction frequency so the most relevant risks appear first, helping you catch second‑ and third‑degree conflicts before engagement.

Requirements

Entity Resolution & Relationship Graph
"As a solo attorney, I want the system to automatically map clients to related people and entities so that indirect conflicts are identified without manual cross-referencing."
Description

Build a persistent, deduplicated graph of people, organizations, and households from CaseSpark intake data, contacts, call logs, and uploaded documents. Link non-obvious relationships such as household member, co-parent, employer/employee, referrer, shared address, and emergency contact. Normalize and canonicalize identifiers (names, emails, phones, addresses) with fuzzy matching, blocker keys, and confidence scoring. Support merge/split operations, versioning, and soft deletes. Expose graph queries via internal services for the conflict engine and integrate with existing CaseSpark identity records and intake workflows.

Acceptance Criteria
Fuzzy Deduplication of Person and Organization Entities
Given two person records from separate intakes with normalized email equal and normalized phone equal When entity resolution runs Then the two records are auto-merged into a single person entity And a matchScore >= 0.95 is recorded on the merge event And canonicalized attributes are stored (name, email, phone, primary address) Given two organization records with Levenshtein(name) <= 2 and identical normalized address When entity resolution runs Then the two records are auto-merged with matchScore >= 0.90 Given two person records that share only a fuzzy name match (Levenshtein <= 2) and no matching normalized email or phone When entity resolution runs Then no auto-merge occurs And a candidate link is recorded with matchScore between 0.60 and 0.89 Given any auto-merge When the merge completes Then provenance for all source records is preserved on the merged entity And an audit log entry is written including source IDs, matchScore, timestamp, and actor = system
Household and Shared Address Relationship Inference
Given two or more person entities share the same normalized residential address with overlapping active date ranges When relationship inference runs Then a Household entity is created (if not existing) And each person is linked to the Household with relationshipType = householdMember and membership startDate Given a person updates to a new primary address When address change is saved Then the prior household membership relationship is endDated with the change timestamp Given two unrelated entities share a non-residential address (e.g., suite or PO Box) When relationship inference runs Then only sharedAddress relationships are created without creating a Household entity Given a household exists When querying the graph for a person’s indirect ties within 2 degrees Then other household members are returned as degree=1 nodes and are included in indirect conflict calculations
Co-Parent, Employer, Referrer, and Emergency Contact Links from Intake
Given a completed intake includes an Other Parent with name and at least one contact identifier (email or phone) When the intake is saved Then a coParent relationship is created between the client and the Other Parent entity Given an intake includes Employer information When the intake is saved Then an Organization entity for the employer is created or resolved And an employerEmployee relationship is created with role=employee Given an intake includes Referred By referencing an existing contact When the intake is saved Then a referrer relationship is created between the referrer and the client Given an intake includes an Emergency Contact When the intake is saved Then an emergencyContact relationship is created between the client and the contact Given all relationships above exist When relationship weights are calculated Then each relationship receives a weight in [0,1] And more recent lastInteractionAt and higher interactionCount in the past 12 months produce a strictly higher weight than older/sparser interactions And relationships are ordered by weight desc in query results
Graph Query API for Conflict Engine (Degrees, Weights, and Explanations)
Given a person entity ID When the conflict engine requests /graph/indirect-ties with degrees=3 Then the service returns persons and organizations up to 3 hops away And results are sorted by riskScore desc where riskScore is a monotonic function of relationship weights and hop distance And each returned node includes at least one explanationPath listing the sequence of relationships and entities connecting to the source Given soft-deleted entities or relationships exist When the conflict engine queries the graph Then soft-deleted items are excluded by default Given a query returning <= 500 nodes and <= 1000 edges When executed under normal load Then p95 latency is <= 500 ms and p99 <= 900 ms Given a request specifies asOfTimestamp When the query is executed Then returned nodes and relationships reflect the versioned state as of that timestamp
Merge, Split, Versioning, and Soft Delete Governance
Given two entities are merged When the merge completes Then a new version is created for the surviving entity with version incremented by 1 And the non-surviving entity receives a redirectTo pointer to the survivor and is soft-deleted And all relationships of the non-survivor are reattached to the survivor preserving original startDate and metadata Given a merged entity must be split When a split operation is performed selecting a subset of source records and relationships Then two valid entities result And relationships and provenance are reassigned accordingly And a complete audit trail is recorded (who, when, what changed) Given any soft-deleted entity or relationship When queried without includeDeleted=true Then it is excluded from results Given a versioned read is requested with asOfTimestamp prior to a merge When the graph is queried with that timestamp Then both pre-merge entities are returned with their pre-merge relationships
Confidence Scoring and Blocker Keys for Candidate Generation
Given candidate generation runs When two records do not share any blocker key (normalized email exact OR normalized E.164 phone exact OR exact street+postal code block) Then they are not considered for pairwise scoring Given two records share at least one blocker key When pairwise scoring runs Then a matchScore in [0,1] is produced based on weighted signals (email, phone, name similarity, address overlap) Given matchScore >= 0.95 When resolution runs Then the pair is auto-merged Given 0.80 <= matchScore < 0.95 When resolution runs Then the pair is not auto-merged And a potentialDuplicate link is created with the score for review Given matchScore < 0.80 When resolution runs Then no link or merge is created
Integration with CaseSpark Identity Records and Intake Workflow
Given a new intake is created for a first-time client When the intake is saved Then a new CaseSpark identity record is created and linked to a newly created canonical entity ID Given a new intake is created for an existing client whose canonical entity exists When entity resolution runs Then the intake’s identity record links to the existing canonical entity ID within 5 seconds Given an entity merge occurs When the merge completes Then all linked identity records and intakes now reference the surviving canonical entity ID And prior IDs resolve via redirect without breaking existing links Given the intake UI requests party search by name, email, or phone When searching Then results include canonical entities only (excluding soft-deleted and redirected records) And results display canonicalized attributes
Tie Weighting & Recency Scoring
"As a practitioner, I want relevant conflict ties to appear first so that I can focus on the highest-risk connections during intake."
Description

Implement a configurable scoring engine that weights relationship edges by interaction frequency, recency, duration, and context (e.g., co-parenting > coworker > referrer). Apply time decay to older interactions. Aggregate edge weights along paths up to third degree to compute overall conflict relevance scores and sort results so the most material risks appear first. Provide firm-level configuration for weights and degree limits, plus thresholds that drive outcomes: Block, Needs Review, or Informational.

Acceptance Criteria
Configurable Context, Frequency, and Duration Weights
Given firm configuration context_weights = {co_parent: 5, household: 4, employer: 3, referrer: 2, coworker: 1} And frequency_multipliers = {daily: 1.5, weekly: 1.2, monthly: 1.0, yearly: 0.7} And duration_multiplier_rule = min(1.0 + 0.1 * full_years, 2.0) When an edge E1 has context = co_parent, frequency = weekly, duration = 3 years Then E1 base_score = 5 * 1.2 * 1.3 = 7.8 When an edge E2 has context = referrer, frequency = yearly, duration = 0 years Then E2 base_score = 2 * 0.7 * 1.0 = 1.4 And updating any config value changes subsequent calculations using the new values And the configuration version_id used is stored with each calculated score
Time Decay Applied to Interaction Recency
Given time_decay_half_life_days = 180 And decay_factor = 0.5 ^ (days_since_last_interaction / 180) When days_since_last_interaction = 0 Then decay_factor = 1.00 ± 0.01 When days_since_last_interaction = 180 Then decay_factor = 0.50 ± 0.01 When days_since_last_interaction = 360 Then decay_factor = 0.25 ± 0.01 And final_edge_score = base_score * decay_factor And decay is applied after duration and frequency multipliers
Path Aggregation with Degree Limit
Given degree_limit = 3 And degree_attenuation = {1: 1.0, 2: 0.6, 3: 0.4} And a simple path P with post-decay edge scores E1 = 8.0, E2 = 5.0, E3 = 2.0 When computing path_score for P Then path_score = 8.0*1.0 + 5.0*0.6 + 2.0*0.4 = 11.8 And paths with length > 3 are ignored And cycles are not traversed (only simple paths considered)
Multiple Paths Aggregation and Ranking Tie-Breaker
Given two simple paths to the same counterparty with path_scores = 12.0 and 9.0 When computing the counterparty overall_score Then overall_score = max(12.0, 9.0) = 12.0 Given two counterparties with equal overall_score When ranking results Then rank the counterparty whose most recent interaction date along its best path is more recent And if still tied, rank alphabetically by counterparty name (A–Z)
Outcome Threshold Mapping to Block, Needs Review, Informational
Given thresholds = {block: >= 80.0, needs_review: 50.0 to 79.99, informational: < 50.0} When overall_score = 83.1 Then outcome = Block and engagement_block = true When overall_score = 50.0 Then outcome = Needs Review and engagement_block = false When overall_score = 49.99 Then outcome = Informational and engagement_block = false
Firm-Level Configuration and Versioning
Given a firm updates weights, degree_limit, half_life, degree_attenuation, and thresholds in settings When the configuration is saved Then values are validated (degree_limit within 1–3; weights and multipliers >= 0; thresholds non-overlapping and ordered) And the configuration is versioned with version_id and effective_at timestamp And subsequent scoring runs for that firm use the latest effective configuration And other firms’ scoring configurations remain unchanged
Handling Missing, Unknown, and Duplicate Relationship Data
Given an edge missing last_interaction_date but with first_seen_date Then days_since_last_interaction = today - first_seen_date Given an edge missing both last_interaction_date and first_seen_date Then apply default decay_factor = 0.5 Given duplicate edges between the same two parties with the same context When building the graph Then merge them by taking the maximum base_score and the most recent interaction dates Given an edge with unknown context Then use context_weights.default = 1.0
Real-time Intake Screening
"As an intake paralegal, I want instant feedback on potential conflicts while collecting information so that I can pause or adjust the intake before investing time."
Description

Deliver streaming conflict checks during intake as data is entered or steps change, returning top N relationship risks within 500 ms at the 95th percentile for typical firm datasets. Display inline indicators and contextual warnings in CaseSpark intake forms and phone-intake consoles. Support partial inputs (e.g., last name + phone) and progressively refine results as more fields are captured. Provide webhooks to push updated risk results to the intake session and matter record.

Acceptance Criteria
Real-time Top-N Risk Latency (P95 ≤ 500 ms)
Given a typical firm dataset of 20k contacts and 80k relationship edges with recency/frequency metadata and 10 concurrent active intake sessions When a user enters or modifies any intake field or changes an intake step in the intake form or phone-intake console Then the system returns the top N relationship risks for that session within 500 ms at the 95th percentile measured over 1,000 updates per environment And the response includes risk_id, score, rank, and top relationship path(s) for each result And no more than 1% of updates exceed 800 ms (p99 ≤ 800 ms)
Partial Input Streaming & Progressive Refinement
Given the user has provided only partial inputs (e.g., last name and phone last-4 or last name and city) When additional identifying fields are added or edited (e.g., first name, full phone, DOB, email, address) Then a refreshed top N list is returned within 500 ms p95 of each input change And results are re-ranked to reflect new confidence, with spurious earlier matches removed when disambiguating data is supplied And the UI preserves cursor focus and does not block typing; results update in place without duplicate rows or jitter And a “matching confidence” label is present for each candidate when inputs are partial
Inline Indicators & Contextual Warnings in Intake UIs
Given one or more risk results exceed the warning threshold for the active intake session When the user is viewing the intake form or phone-intake console Then an inline risk indicator (icon + text) appears adjacent to the party fields within 200 ms of result receipt And selecting the indicator opens a panel showing the top 3 relationship paths, risk scores, and recency/frequency explanations And indicators are non-blocking, dismissible, keyboard navigable, and include accessible labels (ARIA) And indicators update in place on each refresh; no more than one indicator instance is shown per field
Webhook Push of Updated Risk Results
Given a verified HTTPS webhook subscription with shared-secret HMAC is registered for the intake session When relationship risk results are updated for that session or its associated matter record Then a POST is delivered within 1 second p95 of update with JSON containing: event_id, session_id, matter_id (nullable), occurred_at (ISO-8601 UTC), topN array [risk_id, score, rank, relationship_paths, top_reason], and schema_version And each request includes X-Signature (HMAC-SHA256) and X-Idempotency-Key headers And deliveries are at-least-once and ordered per session; retries occur up to 5 times with exponential backoff on non-2xx And duplicate deliveries are ignored by consumers using the idempotency key
Recency/Frequency-Weighted Ranking & Explanations
Given a curated test fixture including households, co-parents, employers, referrers, shared addresses, and emergency contacts with varied interaction counts and timestamps When computing risks for a target party Then relationships with higher recency and interaction frequency receive higher scores and outrank older/low-frequency ties (e.g., co-parent contact within 12 months outranks a shared employer last seen 24+ months ago) And score increases monotonically with recency/frequency within the fixture’s ranges And ties are broken deterministically by strongest path depth then lexicographic by normalized name And each result includes an explanation referencing the highest-weighted path and factors used
Live Entry Resilience: Debounce, Cancellation, Reconnect
Given a user types rapidly (>5 keystrokes/second) or pastes values during intake When input-change events are emitted Then requests are debounced so no more than one conflict-check request is sent per 200 ms per session And any in-flight outdated request is cancelled; only the latest result is rendered And there is at most one active compute per session; stale results do not surface after newer ones And on transient network loss up to 30 seconds, the client auto-reconnects and replays the last payload; duplicated warnings are not displayed
Top-N Parameterization & Result Pagination
Given the client specifies N via a limit parameter between 5 and 50 (default 10) When a conflict-check is requested Then exactly N results are returned when available; if fewer exist, all are returned with has_more=false And ordering is stable across refreshes when inputs are unchanged And changing the limit updates the returned count and ranks accordingly within 500 ms p95
Explainable Conflict Paths
"As an attorney, I want to see why a connection was flagged so that I can make a defensible decision and document the rationale."
Description

Present clear, auditable explanations for each flagged relationship, including path visualization (e.g., Prospect → Shared Address → Former Spouse → Opposing Party), degrees of separation, contributing weights, timestamps, and source records. Allow users to expand nodes to view evidence (e.g., address match details, call log references), annotate with notes, and dismiss with a required reason and retention period. Persist actions to the matter’s audit log and conflict history, exportable as PDF for compliance.

Acceptance Criteria
Visualize Conflict Path With Degrees and Weights
Given a flagged relationship exists for a matter When the user opens the conflict detail view Then the UI renders a path visualization from the prospect to the opposing party including all intermediary nodes And each node is labeled with entity type and display name And the path shows the degree of separation count for the relationship (e.g., 1st, 2nd, 3rd) And each path segment displays contributing weight components (recency, interaction frequency) and the total risk score And each node shows the latest relevant timestamp And the path includes a list of source record identifiers supporting each link
Expand Nodes to View Evidence
Given a path node has one or more evidence sources When the user expands the node Then an evidence panel displays for that node including source type, record ID, matched fields, match strength, and timestamps And address matches show normalized address, match method, and confidence And call log references show call timestamp, caller/callee, and transcript snippet if available And each evidence item links to the underlying record in a new tab And the system records an audit event for evidence_viewed with user, node ID, and timestamp
Annotate Flags With Notes
Given a flagged relationship is displayed When the user adds a note and submits Then the note is saved with author, timestamp, and immutable content And empty notes are rejected and the submit action is disabled until a minimum of 3 characters is entered And the note appears inline under the flag’s explanation and on the matter’s conflict history timeline And an audit log entry is created for note_added with the note ID and user
Dismiss Flag Requires Reason and Retention
Given a flagged relationship is displayed When the user selects Dismiss Then a modal requires a dismissal reason (10–500 characters) and a retention period (date or duration within allowed bounds) And the Confirm action remains disabled until both fields are valid And upon confirmation, the flag is hidden from the active conflict list for the matter until the retention period expires And the flag remains visible in conflict history with dismissal reason and retention end date And an audit log entry is created for flag_dismissed including actor, timestamp, reason, and retention
Persist Actions to Audit Log and Conflict History
Given the matter has explainable conflict paths enabled When a user views a conflict, expands a node, adds a note, dismisses a flag, or exports a report Then the system writes an immutable audit entry per action capturing action type, user ID, matter ID, entity/node IDs, timestamp, and before/after state where applicable And the matter’s conflict history timeline displays these entries in reverse chronological order And audit entries are searchable by action type and date range
Export Explainable Conflict Paths as PDF
Given a matter has one or more flagged relationships and related history When the user selects Export PDF Then the system generates a PDF that includes: cover page (matter ID, client name, export timestamp), per-flag sections with path visualization, degrees of separation, weight breakdown, timestamps, source records, notes, and any dismissal reason with retention And the PDF is available for download within 10 seconds for matters with up to 50 flags And the PDF includes page numbers and a document hash on the footer for integrity And an audit entry is recorded for export_pdf with file hash and page count
Sort and Filter Flags by Weighted Risk
Given multiple flagged relationships exist When the user views the conflict list Then flags are sorted by total weighted risk score descending And ties are broken by most recent relevant timestamp And filters allow narrowing by degree of separation, relationship type, active/dismissed status, and retention expiration window And dismissed flags within their retention period are excluded from the active list but remain accessible in history And each list item displays the total score and weight components
Jurisdiction-Aware Conflict Rules
"As a family-law attorney practicing across jurisdictions, I want conflict evaluations to reflect local rules so that risk assessments match my obligations wherever I file."
Description

Adjust relationship significance and threshold outcomes based on jurisdictional context (e.g., recognition of common-law partners, household definitions, employer-size factors). Determine jurisdiction from matter metadata and allow per-matter overrides. Provide managed rule packs maintained by CaseSpark with versioning and release notes, plus a layer for firm-specific customizations that can enable/disable, reorder, or extend rules without code changes.

Acceptance Criteria
Jurisdiction Selection and Override Precedence
Given a matter with metadata jurisdiction_code="US-CA" and no override When Relationship Lens runs conflict analysis Then the system loads the active rule pack for US-CA and displays the active pack name and version in the analysis header And the audit log records jurisdiction_source="metadata" and the applied rule_pack_id and version Given the same matter with per-matter jurisdiction_override="US-AZ" When the analysis is re-run Then the system uses the US-AZ variant and the audit logs jurisdiction_source="override" And the override persists on the matter and is used by UI and API until cleared Given a matter without jurisdiction_code and no override When analysis is initiated Then the system blocks scoring, prompts to select a jurisdiction or apply the firm default, and records a warning banner until resolved
Managed Rule Packs Versioning and Release Notes
Given the firm has rule pack family "US-FamilyLaw" with versions v2.2 (active) and v2.3 (available) When an admin opens rule pack settings Then release notes for v2.3 are visible and a diff to v2.2 (rules added/changed/removed) can be reviewed When the admin schedules v2.3 to become active on a future date/time Then analyses before that effective time use v2.2 and analyses at/after use v2.3 And each analysis result is stamped with rule_pack_id and version Given v2.3 is causing issues When the admin performs a rollback to v2.2 Then the system immediately applies v2.2 for new runs and preserves an audit trail of schedule/rollback events And matters pinned to a specific version continue to use the pinned version regardless of global active version
Firm Customization Overlay Without Code Changes
Given base rule pack variant "US-CA FamilyLaw v2.3" is active When a firm admin creates an overlay in the UI Then the admin can enable/disable individual rules, reorder evaluation priority, and adjust thresholds per matter_type without code changes And the admin can add a new rule via a no-code builder using conditions on tie_type, recency_days, interaction_frequency, and employer_size When the overlay is published to production Then analyses use base v2.3 + overlay with deterministic merge precedence (overlay overrides base; unspecified items inherit) And an in-product test harness allows running sample matters to compare scores before/after overlay And explanations show which rules fired and whether source=base or source=overlay And only users with the "Rule Admin" role can create/edit/publish overlays
Jurisdictional Relationship Definitions and Weighting
Given two otherwise identical matters with jurisdiction_code="US-TX" and "US-CA" using the same rule pack family variants When Relationship Lens computes significance scores Then the definitions of household, co-parent, and partner/common-law reflect the active jurisdiction variant configuration And weights for tie_type and recency/interaction_frequency exactly match the active variant values And the ordered risk list differs if variant configurations differ; unit tests validate expected ordering for a shared fixture dataset Given jurisdiction_code where common-law partners are not recognized in the variant When a subject has cohabitation=18 months without marriage Then the tie is mapped per the variant (e.g., household, not partner) and receives the configured weight Given jurisdiction_code where common-law partners are recognized in the variant When the same data is evaluated Then the tie is treated as partner and receives the configured partner weight
Outcome Thresholds by Jurisdiction and Matter Type
Given the active variant defines thresholds for matter_type="Divorce" in jurisdiction "US-NY" (e.g., Block>=80, Review 50-79, Clear<50) When an analysis yields total_score=83 Then outcome="Block" is shown with an explanation referencing the thresholds and triggering rules When the firm overlay adjusts the Review lower bound to 45 for matter_type="Divorce" Then subsequent analyses use the updated mapping immediately And API GET /conflicts/{matterId} returns outcome plus thresholds_used reflecting the variant/overlay in effect And re-running historical matters reclassifies outcomes according to current thresholds unless the matter is pinned to a version
Jurisdictional Auditability and Traceability
Given any conflict analysis is executed When viewing the analysis detail or exporting an audit report Then the record includes: detected_jurisdiction, jurisdiction_source (metadata|override|default), rule_pack_id, rule_pack_version, overlay_id, overlay_version, effective_date, enabled_rules list with versions, thresholds_used, and a per-rule evaluation trace (input facts, computed weight, score contribution, outcome) And the audit record is immutable, time-stamped, and exportable as JSON and PDF And access to audit exports is controlled by role permissions and all exports are logged
Admin Policy Console
"As a firm owner, I want to configure how conflicts are detected and surfaced so that the system aligns with our risk tolerance and compliance requirements."
Description

Offer an administrative UI to configure relationship types, weighting policies, path degree limits, result thresholds, enabled data sources, and data retention/masking options. Include a test harness to run sample inputs and preview ranked results before publishing policy changes. Enforce role-based access control, track change history with diffs and rollbacks, and support export/import of policies across accounts or environments.

Acceptance Criteria
Configure Relationship Types & Weighting Rules
Given a user with the Policy Admin role is on the Policy Console When they create a relationship type providing name, description, active flag, base weight (0.00–1.00), recency decay half-life (days, 1–3650), and frequency multiplier (0.00–5.00) Then the system validates presence, numeric ranges, and uniqueness of name within the account and blocks save with inline errors if invalid And when they save, the policy is persisted as a Draft version with timestamp and author; Published policy remains unchanged And when they edit or deactivate an existing type in the Draft, changes are versioned and reversible prior to publish And the Draft displays computed effective weight examples for entered recency/frequency inputs without altering live evaluations
Set Path Degree Limits & Result Thresholds
Given a Policy Admin sets Max Path Degree (1–5), Minimum Risk Score threshold (0.00–1.00), and optional Top-N cap (1–500) When they save the Draft Then values are validated for allowed ranges and logical consistency; invalid values block save with inline errors And Draft values are immediately used in test harness previews and are not applied to live evaluations until published When they publish the policy Then live evaluations enforce the Max Path Degree, exclude results below the threshold, and truncate by Top-N deterministically (tie-break by score then entity name)
Enable/Disable Data Sources & Masking
Given a Policy Admin toggles enabled data sources and configures field-level masking and retention windows (days) per source in a Draft When a source is disabled in the Draft Then test harness previews exclude that source; on publish, live evaluations exclude it And when masking rules are set for non-admin roles Then both previews and live views redact masked fields for those roles while preserving scores And when a retention window is reduced and published Then a purge job is queued immediately, shows status in the console, and deletes records older than the window within 24 hours; deletions are logged by source and count
Test Harness: Run Samples & Preview Ranked Results
Given a policy (Draft or Published) and a sample input with primary party details, optional related entities, and an As-Of date/time When the user runs the test harness Then the system returns a ranked list of potential conflicts including score, path degree, relationship types along the path, contributing data sources, and a breakdown of base/recency/frequency components And the user can toggle Draft vs Published and see side-by-side results with changes in order, inclusion/exclusion, and scores highlighted And test runs are non-persistent and write no data to matters or conflict logs And results can be exported as CSV or JSON including the policy version and As-Of timestamp
Publish, Versioning, Audit Trail, and Rollback
Given at least one Draft change exists When a Policy Admin clicks Publish and enters a required change note Then the system validates the Draft, increments the policy version, activates it for new evaluations within 1 minute, and records author, timestamp, and change note And an audit record stores a structured diff of the publish (added/removed/changed fields with old/new values) When the admin selects a prior version and clicks Rollback with a reason Then the selected version becomes Published, a new audit entry is created with the rollback diff, and the change is effective for new evaluations within 1 minute And publish or rollback attempts by non-admin users return 403 and are logged
Role-Based Access Control (RBAC) Enforcement
Given defined roles: Policy Admin, Policy Editor, Policy Viewer When a Policy Admin accesses the console Then they can create/edit Drafts, use the test harness, publish, export, import, and rollback When a Policy Editor accesses the console Then they can create/edit Drafts and use the test harness but cannot publish, export, import, or rollback; restricted actions return 403 and are logged When a Policy Viewer accesses the console Then they can view the Published policy and run read-only test harness against the Published version but cannot view Drafts or make changes; attempts are logged And permissions are enforced at API and UI layers (UI controls hidden/disabled, API denies unauthorized requests)
Export/Import Policies Across Accounts or Environments
Given a user with the Policy Admin role and a selected policy (Draft or Published) When they export the policy Then the system downloads a signed JSON package containing policy data, metadata (version, author, timestamps), and a SHA-256 checksum When they perform an Import Dry-Run in a target environment Then the system verifies signature, checksum, schema version compatibility, and data-source mappings, and shows a diff and warnings without persisting When they confirm Import Then a new Draft policy is created with mapped identifiers; unmapped sources require explicit mapping or are disabled with warnings; no changes are applied to Published until explicitly published And re-importing the same package is idempotent and does not create duplicate relationship types And export/import actions are captured in the audit log
Retrospective Scan & Backfill
"As a firm administrator, I want to scan our historical database for indirect conflicts so that we can remediate latent risks and update engagement policies."
Description

Provide a batch scanner to retroactively analyze existing contacts and matters for indirect conflicts using the latest graph and policy settings. Schedule off-hours runs, track progress and metrics, deduplicate notifications, and create review tasks for any newly discovered risks. Generate a firm-wide report with severity distribution, top relationship types, and recommended policy adjustments.

Acceptance Criteria
Schedule Off-Hours Retrospective Scan
Given an admin schedules a retrospective scan for an off-hours window and selects a timezone When the job is saved Then the next-run timestamp reflects the selected timezone and the job appears in the schedule queue with status "Scheduled" Given the scheduled time arrives When the scan starts Then the job initiates within 5 minutes of the window start and runs within configured resource ceilings without degrading intake p95 latency beyond configured thresholds Given an admin cancels a scheduled job before start When the scheduled time arrives Then the job does not run and an audit log entry records the cancellation user, timestamp, and reason Given a recurrence is set to daily or weekly When the first run completes Then the next occurrence is enqueued with the same configuration and updated next-run timestamp
Apply Latest Policy and Graph During Scan
Given policy version X is active and the relationship graph snapshot is taken at scan start T When the scan runs Then conflict evaluation uses policy version X and the graph snapshot timestamped T for all records in the run Given a contact/matter has indirect ties whose weighted score meets or exceeds the active threshold When the scan evaluates it Then a risk finding is created with computed severity, relationship path(s), and evidence of weights used Given indirect ties fall below threshold When the scan evaluates them Then no risk findings are created and the record is counted in metrics as "below-threshold" Given policy is updated to version X+1 that increases weights for a tie type When a re-scan is executed Then any newly qualifying risks are created and existing severities are updated, and each finding stores the policy version used and the delta from the prior run Given a previously waived risk exists with waiver scope "policy <= X" When policy decreases severity or remains the same and a re-scan runs Then no new finding or task is created for that same risk key
Progress Tracking and Metrics Visibility
Given a scan is running When a user views the job details Then percent complete, processed/total records, conflicts found by severity, error count, and ETA are displayed and auto-refresh at least every 5 seconds Given an error occurs on a record When processing continues Then the error is logged with the record ID and reason, and the error count increments without stopping the job Given the error rate exceeds the configured threshold (e.g., 5% of last 1,000 records) When the job is running Then the job auto-pauses and alerts admins via in-app and email Given a scan completes When the dashboard is viewed Then final metrics persist and can be exported to CSV with job ID, start/end times, policy version, and counts by severity
Deduplicated Notifications and Digesting
Given a risk finding identical to an existing open task/notification (same risk key: matter/contact, relationship type, parties, policy version) When the scan completes Then no duplicate notification is sent and the finding is linked to the existing task Given a risk was previously resolved/waived with scope covering the current policy version When the scan finds the same relation Then no new notification is sent and the finding is marked as deduplicated by waiver Given more than 5 new findings are created for a single matter in a run When notifications are sent Then recipients receive one aggregated email digest and one in-app notification with a summarized count and links to detail Given multiple channels (email and in-app) are enabled When notifications are sent Then each user receives at most one email per job and can view the full list in-app
Automatic Review Task Creation for New Risks
Given a new High-severity risk is created by the scan When tasks are generated Then a review task is created and assigned to the designated conflicts manager with due date within 2 business days and includes links to the matter/contact and relationship path details Given a new Medium-severity or Low-severity risk is created When tasks are generated Then due dates are set within 5 and 10 business days respectively and SLA tags are applied accordingly Given an open review task already exists for the same risk key When the scan completes Then no new task is created and the existing task receives a comment referencing the new finding and scan job ID Given task creation encounters a transient failure When retries occur Then the system retries up to 3 times with exponential backoff and logs success or final failure in the job summary
Firm-Wide Backfill Report Generation
Given a scan completes successfully When the firm-wide report is generated Then it includes total records scanned, total risks found, severity distribution (counts and percentages), top 10 relationship types by occurrence and by average severity, and impacted matters by count Given the recommendation engine analyzes near-threshold findings When the report is generated Then it outputs at least three suggested policy adjustments with the tie types affected and the projected impact on false positives/negatives Given an admin views the completed report When they export it Then CSV and PDF downloads include run ID, policy version, timestamps, and are stored with 365-day retention and access-limited to admins Given a non-admin attempts to access the report When authorization is checked Then access is denied and the attempt is logged
Pause, Resume, Cancel, and Failure Recovery
Given a scan is running When an admin clicks Pause Then the job pauses within 60 seconds, persists a checkpoint, and UI status changes to "Paused" Given a scan is paused When an admin clicks Resume Then the job resumes from the last checkpoint without reprocessing completed records Given a transient system error occurs When processing a batch Then the job retries that batch with exponential backoff up to 5 attempts; on final failure the job status is set to "Failed" and an error summary is emailed to admins Given multiple jobs are scheduled for the tenant When one job is running Then only one retrospective scan runs concurrently and additional jobs remain queued until resources are available Given a job is canceled by an admin When cancellation completes Then partial findings are discarded, no notifications or tasks are emitted, and an audit log records user, timestamp, and reason

Precision Tuner

Gives fine‑grained control over fuzzy‑match sensitivity by stage and matter type. Use broad matching for first‑call triage and strict rules for final checks, then validate settings in a sandbox that estimates false positives/negatives against your history. Save presets by role to align noise levels with each user’s workflow.

Requirements

Stage- and Matter-Specific Sensitivity Profiles
"As a managing attorney, I want to set different match sensitivities by workflow stage and matter type so that intake staff can move quickly while final checks remain rigorous and compliant."
Description

Provide administration controls to define fuzzy-match thresholds and matching rules per intake stage (e.g., First-Call Triage, Pre-Engagement, Final Conflict Check) and per matter type (e.g., Divorce, Custody, Adoption). Profiles include tokenizer options, phonetic and nickname handling, synonym lists, and similarity thresholds. The workflow engine automatically applies the correct profile when a stage is reached or matter type is assigned/changed. Supports a firm-wide default with stage or matter-level overrides. Exposes profile selection in workflow configuration, surfaces the active profile in the screening UI, and records the profile used on each screening run for traceability. Optimizes speed in early stages while enforcing strict checks before filing.

Acceptance Criteria
Auto-apply Profile on Stage Transition
Given a matter in First-Call Triage with matter type Divorce and profiles configured for all stages When the workflow advances the matter to Pre-Engagement Then the active fuzzy-match profile switches to the Pre-Engagement:Divorce profile within 1 second And the screening service uses the new profile for all subsequent conflict queries on that matter And the screening UI updates to display the new active profile name and version immediately
Override Precedence: Firm Default < Stage < Matter Type
Given a firm-wide default profile D, a stage override profile S for Pre-Engagement, and a matter-type override profile M for Divorce When a Divorce matter is in Pre-Engagement Then the active profile is M When the matter type has no override but the stage has S Then the active profile is S When neither override exists Then the active profile is D
Admin Defines Stage- and Matter-Specific Profile
Given an administrator with profile-management permissions When the admin creates or edits a profile specifying tokenizer option, phonetic and nickname handling toggles, synonym list entries, and similarity thresholds per entity type Then similarity thresholds outside 0.00–1.00 (to two decimals) are rejected with inline errors and save is blocked And duplicate synonyms (case-insensitive) are prevented with a clear error message And a saved profile is assigned a unique ID, human-readable name, version number, and scope (Firm Default, Stage, or Matter Type) and becomes available in selection lists within 5 seconds
Workflow Config: Profile Selection and Application
Given the workflow configuration UI supports a stage node setting: Profile Mode {Use System Selection | Force Profile} When an admin sets Final Conflict Check to Force Profile = "Strict v2" Then at runtime the engine uses "Strict v2" for that stage regardless of matter type When the stage node is set to Use System Selection Then the engine computes the active profile using the precedence rules (Firm Default < Stage < Matter Type) And configuration changes apply to screenings triggered after the change and do not alter profile data stored on past runs
Active Profile Visible in Screening UI
Given a user viewing the screening panel for a matter When the panel loads Then the UI displays the active profile name, version, selection source (Default/Stage/Matter/Forced), current stage, and matter type above the results And the profile name links to read-only profile details in a side panel
Screening Run Records Profile Used
Given a screening is executed for a matter When the run completes Then the run record stores profile_id, profile_name, profile_version, selection_source, stage, matter_type, and timestamp And the run history view and export include these fields for every run And subsequent profile changes do not modify stored profile metadata on prior runs
Matter Type Change Triggers Profile Update and Re-screen Prompt
Given a matter in Pre-Engagement with active profile for Divorce and existing screening results When the matter type is changed to Custody Then the active profile recomputes to the Pre-Engagement:Custody profile within 1 second And a non-blocking banner prompts the user to re-run screening due to the profile change with a single-click Re-run action And the audit trail records the old and new profiles associated with the change
Historical Sandbox Accuracy Estimator
"As a risk-conscious attorney, I want to validate a sensitivity profile against my past cases so that I can quantify accuracy and risk before enabling it in production."
Description

A non-production sandbox to evaluate tuning profiles against historical matters and conflict records, estimating false positives/negatives before deployment. Allows selecting date ranges, matter types, and sample sizes; anonymizes PII with reversible in-memory tokenization. Produces precision/recall, FPR/FNR, confusion matrix, top false negatives, and estimated time saved, with exportable reports. Executes on isolated compute without altering production data or settings. Integrates with CaseSpark’s conflict index and matter archive; stores scenario results for comparison and governance reviews.

Acceptance Criteria
Filtered Historical Run Generates Core Accuracy Metrics
Given I am an authorized user with "Sandbox:Run" permission And I select a tuning profile and filters: date range, matter types, and sample size N When I execute the Historical Sandbox Accuracy Estimator Then the system evaluates the filtered historical records against the profile and returns precision, recall, FPR, FNR, and a confusion matrix (TP, FP, TN, FN) And the sample size honored is exactly N (or all eligible records if fewer than N) And all metrics are computed only over records matching the filters And the run is assigned a unique Scenario ID and stored with profile version, filters, timestamp, and user And no production data or settings are modified
PII Tokenization Is Reversible In-Session and Never Persisted
Given sandbox data includes PII fields (name, email, phone, address, SSN/Tax ID) When the run begins Then all PII fields are replaced with format-preserving tokens before any matching computation And the token map exists only in memory for the active sandbox session And exports, logs, and stored results contain only tokens, never raw PII And detokenization is possible only during the active session by users with "Sandbox:RevealPII" permission on a per-record basis And every detokenization event is audit-logged with user, record, timestamp, and reason
Isolated Compute and Read-Only Integrations
Given the estimator is executed Then it runs on isolated compute resources with credentials separate from production And connections to the matter archive and conflict index are read-only And any attempt to perform a write is blocked and recorded as a security event And network egress from the sandbox is restricted to approved endpoints
Exportable Report Includes Metrics, Top FNs, and Time Saved
Given a completed sandbox run When I request an export Then I can download a report in PDF and CSV/JSON formats And the report includes precision, recall, FPR, FNR, confusion matrix, top K false negatives (tokenized), and estimated time saved And estimated time saved is calculated using admin-configured baseline review times per stage and observed error rates from the run And the report references the run’s Scenario ID, profile version, filters, and timestamp And the export completes within 10 seconds for runs up to 10k evaluated records
Top False Negatives List Supports Review
Given a completed run with false negatives When I open the Top False Negatives view Then items are ranked by risk score or impact And I can view contributing match features and thresholds that led to the miss (tokenized context) And, with "Sandbox:RevealPII" permission, I can detokenize a single item within the session And I can mark items as Reviewed and add a note And notes are stored with the scenario for governance review
Scenario Result Storage and Cross-Profile Comparison
Given multiple sandbox runs have been stored When I select two or more runs to compare Then the UI shows side-by-side metrics and deltas for precision, recall, FPR, FNR, and counts (TP/FP/TN/FN) And statistically significant regressions (e.g., ≥1.0% absolute drop in recall) are highlighted And I can filter stored runs by date range, matter type, profile, and user And only authorized roles can access stored scenarios and comparisons
Role-Based Presets and Permissions
"As an operations manager, I want to assign tuned presets to roles so that each team has an appropriate noise level without manual tweaking on every workstation."
Description

Enable saving, sharing, and assigning Precision Tuner presets by role (e.g., Intake Specialist, Associate, Partner) and location. Admins can set role defaults, lock presets, and allow per-user overrides with optional approval. Presets encapsulate thresholds, dictionaries (synonyms, nicknames), and exclusion rules. Integrates with CaseSpark user/role management and SSO groups. Changes propagate on next session and are fully audit logged. Supports preset discovery, descriptions, and tagging for easy selection.

Acceptance Criteria
Save and Assign Role- and Location-Scoped Preset
Given I am an Admin with permission to manage Precision Tuner presets When I create a new preset that includes thresholds, dictionaries (synonyms, nicknames), and exclusion rules, add a description and tags, and assign it to role "Intake Specialist" scoped to location "California" Then the preset is saved with all fields persisted And the preset is discoverable by name, description, and tag by eligible users And only users whose role is Intake Specialist in location California can see and select it And users outside that role or location cannot see it in search, browse, or API listing
Role Default and Lock Enforcement
Given an Admin sets preset X as the default for role "Associate" in location "Texas" and marks it Locked When a user with role Associate in Texas starts a new session Then preset X auto-applies as the active preset And UI controls to modify thresholds, dictionaries, and exclusion rules are disabled with a lock indicator And attempts to save a new preset or switch to a non-approved preset are blocked with an explanatory message And the lock applies regardless of the user's prior active preset
Per-User Override with Approval
Given the organization has enabled per-user overrides with approval and preset Y is the locked default for role "Associate" in Texas When user U (Associate, Texas) proposes an override derived from preset Y and submits for approval Then an approval request is created and routed to designated approvers And approvers can approve or reject within the app And upon approval, the override is stored as a user-scoped preset for U only and becomes active on U's next session And upon rejection, the override is not stored or activated And all steps (request, decision, activations) are audit logged
SSO and Role Mapping Enforcement
Given SSO group G maps to role "Intake Specialist" and location "California" in CaseSpark When a user's SSO group membership changes from G to H, where H maps to role "Partner" and location "Nevada" Then on the user's next session, presets available and defaults reflect the Partner/Nevada scope And the user no longer has access to presets scoped to Intake Specialist/California And an audit log entry records the role/location change and preset access changes
Audit Logging of Preset Lifecycle and Access Changes
Given any action that creates, updates, locks/unlocks, assigns, approves/rejects, or deletes a preset, or changes user/role/location mapping When the action is performed via UI or API Then a tamper-evident audit log entry is recorded with actor identity, timestamp (UTC), action type, entity ID, scope (roles, locations, users), source (UI/API/SSO), and before/after values for changed fields And audit entries are immutable and queryable by time range, actor, action type, entity, role, and location
Preset Discovery, Filtering, and Performance
Given a user eligible to use presets opens the preset selector When they search by keyword or filter by tag, role, location, updated-by, or locked status Then results include presets the user is authorized to see and exclude others And search is case-insensitive and supports partial matches on name, description, and tags And opening a preset shows a non-editable preview of thresholds, dictionaries, and exclusion rules And for an organization with up to 500 presets, 95th percentile search response time is <= 500 ms
Next-Session Propagation Semantics
Given a change to presets or assignments is made (create, update, lock, unlock, assign, approve) When a user is currently signed in Then the user's active session continues using the previously active preset without mid-session change And on the user's next sign-in, the latest assigned/default/approved preset becomes active
Side-by-Side Impact Preview
"As an intake lead, I want to compare two sensitivity settings side-by-side so that I can choose the configuration that best balances speed and accuracy for my team."
Description

Interactive UI to compare two sensitivity profiles on the same sample dataset, showing differences in matches, near-misses, and estimated review time. Provides entity-level drill-down with similarity score components and rationale (e.g., phonetic match, nickname expansion). Integrates within the tuner modal and leverages the sandbox sampling service. Supports saving the comparison, commenting, and promoting the selected profile to a preset with one click.

Acceptance Criteria
Side-by-Side Counts and Deltas
Given two saved sensitivity profiles A and B and a pinned sample dataset ID D from the sandbox When the user opens the Side-by-Side Impact Preview Then both panels load using dataset D within 2 seconds And for each profile the UI shows counts for Matches, Near-Misses, Non-Matches, and an Estimated Review Time with units And the delta between A and B is shown for each metric with +/− indicators And Matches + Near-Misses + Non-Matches equals the dataset size And reopening the preview with the same D yields identical counts and estimated times
Sample Dataset Consistency and Reproducibility
Given the user generates a sample via the sandbox with seed S When they click "Use this sample" Then a dataset ID D and seed S are displayed And both panels use D for all calculations And rerunning the comparison with seed S reproduces the same entity list and metrics And toggling "Refresh sample" replaces D and updates metrics accordingly And if the sandbox is unavailable Then an inline error with Retry is shown and no stale results are displayed
Entity Drill-Down with Similarity Rationale
Given the comparison is loaded When the user clicks a Matches or Near-Misses count for profile A Then a paginated entity list opens showing entity name, identifiers, decision (A vs B), and top similarity score When the user selects an entity Then a detail view shows overall similarity scores for A and B, thresholds applied per profile, component contributions (e.g., phonetic, nickname, token distance) with percentages, and rationale text per component And the rationale indicates which components caused A and B to differ
Change-Focused Filtering and Sorting
Given an entity list is open When the user toggles "Only show changes" Then only entities with different decisions or score deltas ≥ 0.01 between A and B are listed When the user applies filters (change type, score delta range, entity type) Then results update within 300 ms and active filters are shown as chips When sorting by "Largest Time Impact" Then results are ordered by the entity-level contribution to estimated review time delta
Save Comparison Snapshot with Share Link
Given a loaded comparison A vs B on dataset D When the user clicks "Save Snapshot" Then a read-only snapshot is created storing profile names and versions, thresholds, dataset ID, seed, timestamp, user, active filters, and notes And a shareable link is generated And opening the link reproduces the same counts, lists, drill-down details, and UI state And a "Snapshot" badge is displayed indicating immutability
Inline Comments and Mentions
Given a loaded comparison or entity detail When a user with Comment permission posts a comment Then it appears in a thread with author and timestamp and is editable for 10 minutes When the user @mentions a teammate Then that teammate receives a notification When viewing a snapshot Then new comments are allowed without changing analytics, and deletions are soft-deleted with an admin-visible audit trail
One-Click Promote to Preset with Role Guardrails
Given profile B is selected in the preview When a user with "Manage Presets" permission clicks "Promote to Preset" and selects a role Then a preset is created or updated with B's settings and role scope and appears in the Presets list immediately And a success confirmation is shown and a change log records actor, before/after, and a rollback option for 7 days When a user without the permission attempts promotion Then the control is disabled with a tooltip indicating the required permission
Preset Versioning and Audit Trail
"As a compliance officer, I want a complete change history and linkage of presets to screening runs so that I can demonstrate due diligence and revert problematic configurations if needed."
Description

Automatic versioning for every preset change, capturing author, timestamp, parameter diffs, comments, and approval status, with rollback capability. Immutable audit trail ties each screening run to the preset and version used via correlation IDs. Supports export to firm audit reports and retention policy configuration. Enables review workflows with approvers and notifications to meet governance requirements.

Acceptance Criteria
Auto-version on preset save
Given a user edits an existing preset's parameters When the user clicks Save Then the system creates a new immutable version (version number increments by 1) And records author user ID, UTC timestamp (ISO 8601), and a field-level parameter diff And stores an optional free-text comment up to 2,000 characters And sets approval status to Draft by default And leaves all prior versions unchanged and viewable
Role-restricted rollback to prior version
Given a user with Preset Admin role opens a preset's version history And selects a prior version Vn When they confirm Rollback with a required comment Then the system creates a new version Vn+1 that clones Vn's parameters And preserves a linkage to the source version and logs a "Rollback" action with author and timestamp And sends notifications to watchers and approvers And does not delete or mutate any historical versions
Audit trail linking screening run to preset version
Given any screening run (triage or final check) is executed When the run starts Then the system assigns a unique correlation ID (UUIDv4) And records preset ID and version number used, actor, timestamp, and run context (stage, matter type) And makes the audit record read-only within 1 second of completion And subsequent preset edits do not change the run's recorded preset/version
Approval workflow enforcement for production use
Given a preset version status is Draft or Pending Approval When a production screening run attempts to use it Then the run is blocked with a clear error and the attempt is logged Given a preset version is Approved by a user other than the author When used in production Then the run proceeds and the approval record is linked in the audit trail And approvers receive notifications on submit and on decision And sandbox runs may use Draft or Pending versions, with the run context marked as Sandbox in the audit record
Export audit report with version lineage
Given an Admin requests an export for a date range and matter types When the export is generated Then the system produces CSV and JSON files containing version history, diffs, comments, approvals, correlation IDs, and retention tags And it includes a PDF summary with counts and exceptions And for datasets up to 10,000 records the export completes within 60 seconds And the export is checksum-signed (SHA-256) and downloadable for 7 days with access control enforced
Retention policy configuration and enforcement
Given a retention policy is configured (e.g., 7 years) and an optional legal hold list When nightly retention processing runs Then audit records and versions older than the policy are archived or purged per setting And any version referenced by a screening run is retained (not purged) to preserve audit integrity And all deletions/archives are logged with who, when, and why And admins can run a pre-execution report of items scheduled for purge
Parameter diff accuracy and completeness
Given a preset is changed across stages and matter types When the version diff is viewed Then only changed fields are listed with old and new values, including nested keys (stage/matter-specific thresholds) And diffs are available in human-readable view and JSON Patch (RFC 6902) format And no spurious changes appear when non-functional metadata changes (e.g., sort order) And automated tests validate at least 95% code coverage for the diff generator across representative fixtures
Compliance Guardrails and Policy Templates
"As a managing partner, I want guardrails that prevent unsafe sensitivity settings so that our firm remains compliant and avoids missed conflicts before filing."
Description

Built-in policy templates per jurisdiction and practice area that define minimum sensitivity floors and mandatory match rules for final checks. The tuner enforces policy floors, warns on attempted violations, and requires documented justification and approval for overrides. Integrates with CaseSpark’s jurisdiction detection and updates templates when regulations change. Provides firm-wide policy management, alerts, and reporting on policy adherence.

Acceptance Criteria
Final Check Policy Floor Enforcement
Given a matter with jurisdiction = "CA" and practice area = "Family Law" and stage = "Final Check" And the active policy template defines a minimum sensitivity floor of 0.92 When a user attempts to save a tuner sensitivity of 0.85 for Final Check Then the system blocks the save And displays an inline error: "Sensitivity must be ≥ 0.92 per policy" And auto-sets the sensitivity to 0.92 And records an audit log entry with user, attempted value, enforced value, policy template ID, and timestamp
Mandatory Rules Enforcement at Final Check
Given mandatory match rules are defined in the active template for the Final Check stage When a user attempts to disable a mandatory rule or change its severity to optional Then the control is disabled or reverts immediately to required And a non-dismissable tooltip explains enforcement per policy And an audit event is recorded with user, rule ID, and timestamp And the Final Check run executes with all mandatory rules applied
Override Justification and Approval Workflow
Given a user attempts to override a policy floor or mandatory rule for a specific matter When the user clicks "Request Override" and enters a justification of at least 20 characters and selects scope = "This check only" Then the system routes the request to an approver with role = "Managing Partner" via in-app task and email And the matter cannot proceed to filing while the override is Pending And upon approval the override applies only to the specified check and expires immediately after execution And upon rejection the policy settings are reapplied and the user is notified And an immutable audit trail captures requester, approver, decision, timestamps, justification text, and affected settings
Jurisdiction-Driven Template Switching
Given jurisdiction detection returns "NY" and matter type = "Divorce" And the "NY - Family Law" policy template is active When the jurisdiction changes to "NJ" via user edit or updated detection Then the active policy template switches to "NJ - Family Law" within 1 second And the UI highlights changes to floors and mandatory rules And any non-compliant current tuner settings are auto-corrected to meet the new policy And a banner logs: previous template, new template, versions, and timestamp
Regulatory Update Propagation and Versioning
Given a policy source update increases the CA Family Law sensitivity floor from 0.90 to 0.95 When a Policy Admin reviews the diff and clicks Accept Update Then a new template version is published and applied to matters created after acceptance And in-progress matters prompt to adopt the update with option to defer up to 7 days with justification And reporting shows rollout status by matter count and percentage And a rollback to the prior version is available for 24 hours with mandatory change note
Policy Adherence Alerts and Reporting
Given policy enforcement is enabled firm-wide When a user attempts a policy-violating change or an override is approved or rejected Then real-time alerts are sent via in-app and email with matter ID, user, rule/policy reference, action, and status And a daily adherence report provides counts of violation attempts, blocked saves, pending overrides, approved/denied overrides, adherence rate by role, and top rules by violation attempts And reports are filterable by date range, jurisdiction, practice area, and user And CSV export includes all visible fields and filters

Why Match

Explains each hit in plain language with factor weights—shared phone, alias similarity, cohabitation window, employer overlap—so attorneys can decide quickly and confidently. Highlights the exact matching fields, flags data quality risks (e.g., recycled numbers), and links to the audit trail for instant defensibility.

Requirements

Factor Breakdown Panel
"As a solo attorney, I want a clear breakdown of why a conflict hit was triggered so that I can decide quickly and document my reasoning with confidence."
Description

Presents a plain-language, factor-weighted explanation for each conflict-screening hit, showing how signals such as shared phone numbers, alias similarity, cohabitation time windows, and employer overlap contributed to the overall match confidence. Pulls factor weights directly from the matching engine, normalizes them, and renders an ordered list of drivers with percentage contribution, match type (exact/fuzzy/phonetic), and recency. Supports expand/collapse, sorting by impact, and hoverable tooltips that define each factor in legal terms. Integrates with CaseSpark’s intake results view and conflict queue, enabling attorneys to decide quickly and consistently while maintaining explainability. Emits structured telemetry for tuning and stores explanations alongside the screening result for reproducibility.

Acceptance Criteria
Factor Breakdown Display & Normalization
Given a conflict-screening hit with factor weights from the matching engine When the Factor Breakdown Panel renders Then it retrieves the raw factor weights for that hit from the engine API and normalizes them to percentages that sum to 100% ±0.1% And each factor row shows: factor display name, normalized percentage with 1 decimal place, match type in {exact,fuzzy,phonetic}, and a recency label (e.g., "3 months ago") with an ISO 8601 timestamp available via tooltip And factors are ordered by normalized percentage descending by default, with ties broken by most recent first And the panel renders the first 10 factors immediately, showing a "Show more" control when more than 10 factors exist And initial render completes within 400 ms at p95 for results containing up to 20 factors on a standard workstation profile
Sorting by Impact and Expand/Collapse Behavior
Given the Factor Breakdown Panel is visible When the user toggles the expand/collapse control Then the factor list collapses/expands without losing state, and the header remains visible with the top driver and total number of factors And the expanded/collapsed state persists for that hit within the current session When the user changes the sort mode Then the list reorders within 100 ms and supports the following modes: Impact (percentage desc), Recency (newest first), Factor Name (A→Z) And the selected sort mode persists for that user until changed again And keyboard users can focus and activate both the toggle and sort controls using Tab/Enter/Space
Legal-Term Tooltips and Accessibility Compliance
Given a factor name or risk badge in the panel When the user hovers or focuses the info icon Then a tooltip appears within 150 ms containing a concise legal-definition (≤240 chars) and, if available, a citation link And the tooltip can be dismissed with Escape and does not obstruct adjacent controls And all interactive elements in the panel are reachable via keyboard and announce meaningful labels to screen readers And color contrast for text, icons, and badges meets WCAG 2.1 AA And on touch devices, tapping the info icon toggles the tooltip and tapping outside dismisses it
Integration in Intake Results and Conflict Queue with Audit Trail Link
Given a user is viewing a screening hit in Intake Results or the Conflict Queue When the user opens the hit details Then the Factor Breakdown Panel is present, styled consistently in both locations, and populated for that hit And an "Audit Trail" link is visible to authorized users and hidden from unauthorized users When the user activates the Audit Trail link Then a new tab opens to the pre-filtered audit trail for the same screening_id and hit_id and loads within 2 seconds at p95 And the originating view remains unchanged and back navigation returns to the prior list position
Data Quality Risk Flagging (e.g., Recycled Numbers)
Given a factor includes a data quality risk flag from the engine or data source (e.g., recycled_number, stale_address, unverifiable_employer) When the Factor Breakdown Panel renders Then the affected factor shows a "Data Quality Risk" badge with a specific risk type label and an info tooltip explaining the risk and its implications And a summary of active risk flags appears in the panel header when any risks are present And risk flags are included in the stored explanation snapshot and visible upon re-open
Structured Telemetry for Explainability Tuning
Given telemetry is enabled When the Factor Breakdown Panel renders Then a factor_breakdown_viewed event is emitted containing: screening_id, hit_id, factor_count, top_3_factor_keys, normalization_version, default_sort, and user_role, with no PII beyond IDs When the user interacts (expand, collapse, sort change, tooltip open, audit_trail_click) Then corresponding events are emitted with interaction type and relevant parameters And 99% of events are acknowledged by the telemetry endpoint within 5 seconds, with up to 3 retries using exponential backoff on failures And all events validate against the agreed JSON schema
Persisted Explanations for Reproducibility
Given a screening result is saved When the system stores the hit details Then it persists an explanation snapshot including: factor keys, raw weights, normalized percentages, match types, recency timestamps, risk flags, factor order, engine_version, and normalization_version And reopening the hit within 365 days reproduces the same ordered list and percentages as the snapshot regardless of later engine changes And if the current engine version differs from the snapshot, the panel labels the explanation as "As of engine vX.Y" And the snapshot is available in export (JSON/PDF) with a checksum for integrity verification
Highlight Matched Fields
"As a paralegal, I want the specific matching fields highlighted so that I can verify the hit without digging through raw data."
Description

Visually highlights the exact fields that matched across entities (e.g., phone, email, aliases, addresses, employers) within intake records and third-party data, annotating each with the match type, source system, timestamp, and provenance. Clicking a highlight reveals the source record and any transformations (normalization, tokenization) applied during matching. Works consistently in the web UI and printable views, with accessible color/contrast and keyboard navigation. Integrates with CaseSpark’s record viewer and supports cross-jurisdiction field schemas.

Acceptance Criteria
Highlight Matched Fields in Web UI
Given an intake matter has at least one entity match result from the matching engine When the user opens the Why Match panel within the record viewer Then every field returned as matched by the engine (phone, email, alias, address, employer) is visually highlighted adjacent to the corresponding field value And no non-matched fields are highlighted And the count of highlighted fields equals the count of matched fields in the match payload for that matter And the highlight style uses the designated design token for match highlighting consistently across screens
Match Metadata Annotation
Given at least one highlighted field is rendered When the UI displays the highlight Then an inline annotation shows match type (one of: exact, fuzzy, phonetic, normalized), source system name, match event timestamp in ISO 8601 with timezone, and a provenance ID And the provenance ID links to the corresponding audit trail entry in a new tab And all metadata values are non-empty and validated against allowed enumerations And a hover/focus tooltip exposes the same metadata for assistive access
Click to Reveal Source Record and Transformations
Given a highlighted field is visible and focusable When the user clicks the highlight or presses Enter/Space while focused Then a side panel opens showing the raw source record values and a step-by-step list of applied transformations (normalization, tokenization, comparator functions) with timestamps And the side panel loads within 1.5 seconds at p95 with 0 client errors at p95 over the last 7 days And the panel provides copy-to-clipboard for source values and a deep link to the full record in the record viewer And pressing Esc closes the panel and returns focus to the originating highlight
Accessible Highlighting and Keyboard Navigation
Given a user relies on assistive technologies When the Why Match UI is rendered Then highlight indicators meet WCAG 2.2 AA contrast (≥ 4.5:1) and do not rely on color alone (includes icon/pattern) And each highlight is reachable via Tab in a logical order, has a visible focus style, and is operable with Enter/Space And screen readers announce role "button" with a name that includes the field label and match type, plus state information And no keyboard trap exists; Shift+Tab returns focus correctly And automated a11y checks (axe) report zero critical violations on the Why Match view
Printable/PDF View Consistency
Given the user selects Print or Export PDF for a matter with matches When the printable view is generated Then every matched field is denoted with a non-color indicator (e.g., superscript marker) that maps to a legend containing match type, source, and timestamp And hyperlinks to the audit trail are preserved as URLs or QR codes where supported And page breaks do not separate a field from its corresponding legend entry And the printable view renders within 3 seconds at p95
Cross-Jurisdiction Schema Support
Given matters use different jurisdiction field schemas (e.g., CA, TX, NY family-law variants) When Why Match highlights are computed Then fields are correctly mapped to canonical entities and highlighted regardless of local field name differences And locale-aware normalization is applied (e.g., E.164 phone, jurisdiction-specific address formatting) and displayed in the transformations list And unknown or unsupported fields are ignored without error and reported in a non-blocking "Unmapped fields" section of the side panel And test fixtures for at least 10 jurisdictions pass with 0 mapping errors
Deep Linking and Record Viewer Integration
Given a highlighted field in the Why Match section When the user selects "Open in Record Viewer" Then the app navigates to the record viewer with a deep link that scrolls and focuses the corresponding field And browser back/forward restores the previous Why Match state and focus And the deep link is shareable and loads the correct highlight state when opened in a new session And unauthorized users are redirected to login and returned to the deep link after authentication
Data Quality Risk Flags
"As an intake specialist, I want data quality risks called out so that I can avoid false conflicts and follow the right verification steps."
Description

Detects and flags data quality risks that can distort match explanations—such as recycled phone numbers, VOIP lines, common-name collisions, PO Boxes, stale addresses, and low-confidence OCR—providing reason codes, evidence, and recommended next steps (e.g., request alternate contact, verify DOB). Displays risk severity badges alongside each factor explanation and adjusts the overall confidence recommendation when appropriate. Integrates with carrier and enrichment lookups where available and logs risk evaluations in the audit trail.

Acceptance Criteria
Flag Recycled Phone Numbers
Given a party phone number is included in a match explanation And a carrier lookup returns reassigned=true with last_change_date <= 90 days When the Why Match explanation is rendered Then a risk badge labeled "Recycled Number" with severity "High" is shown adjacent to all phone-number-based factors And reason code "RISK_PHONE_RECYCLED" is displayed with evidence: last_change_date, carrier_name, line_type And recommended next steps include "Request alternate contact number" and "Verify via 2FA or call-back" And the overall confidence recommendation is decreased by the configured High severity delta and the delta value is shown And the evaluation is recorded in the audit trail with ISO-8601 timestamp, correlation ID, inputs hashed, and third-party response reference And if last_change_date is between 91 and 365 days, severity is "Medium" and the configured Medium delta is applied And if last_change_date is > 365 days or unknown, severity is "Low" and no confidence delta is applied
Flag VOIP Lines
Given a party phone number is present in the explanation inputs And carrier/enrichment lookup returns line_type = "VOIP" or cnam_category = "VoIP" When the explanation is rendered Then a "VOIP Line" risk badge with severity "Medium" is displayed adjacent to phone-number-based factors And reason code "RISK_VOIP" is shown with evidence: line_type, provider_name And recommended next steps include "Collect an alternate non-VoIP phone" and "Use multi-factor identity checks" And the overall confidence recommendation is reduced by the configured Medium delta and the delta value is shown And the risk evaluation is logged to the audit trail with request ID and lookup reference And if line_type is unknown or unavailable, no VOIP risk is displayed and no confidence delta is applied
Flag Common-Name Collisions
Given a candidate match is supported only by name or name+city and lacks DOB, SSN, or other unique identifiers And the name frequency rank in the relevant jurisdiction is within the top 1% most common When the explanation is rendered Then a "Common-Name Collision" risk badge with severity "Medium" is displayed adjacent to name-based factors And reason code "RISK_COMMON_NAME" is shown with evidence: name_frequency_percentile, missing_identifier_fields, factor_overlap_count And recommended next steps include "Request DOB or middle name" and "Confirm address history" And the overall confidence recommendation is decreased by the configured Medium delta and the delta value is shown And upon adding a unique identifier (e.g., DOB), the risk badge is cleared and the prior delta is removed on re-evaluation
Flag PO Boxes and Stale Addresses
Given an address-based factor contributes to the match explanation And USPS/DPV indicates is_po_box = true When the explanation is rendered Then a "PO Box" risk badge with severity "Low" is displayed adjacent to address-based factors And reason code "RISK_PO_BOX" is shown with evidence: dpv_code, address_line1 And recommended next steps include "Request residential street address" and "Collect alternative proof of residency" And no confidence delta is applied for Low severity And the evaluation is logged to the audit trail with the DPV evidence reference Given an address has enrichment metadata address_last_seen_date > 18 months ago When the explanation is rendered Then a "Stale Address" risk badge with severity "Medium" is displayed adjacent to address-based factors And reason code "RISK_ADDRESS_STALE" is shown with evidence: address_last_seen_date, source_name And the overall confidence recommendation is decreased by the configured Medium delta and the delta value is shown
Flag Low-Confidence OCR on Key Fields
Given person-identifying fields were OCR-extracted with per-field confidence scores And any key field (name, DOB, address) has confidence < 0.70 When the explanation is rendered Then a "Low-Confidence OCR" risk badge with severity "High" is displayed adjacent to factors derived from those fields And reason code "RISK_OCR_LOW_CONF" is shown with evidence: field_name, confidence_score, source_document_id And recommended next steps include "Re-upload a clearer document" or "Manually verify values" And the overall confidence recommendation is decreased by the configured High delta and the delta value is shown And auto-propagation from those fields is blocked until confirmation And if all key fields are between 0.70 and 0.85, severity is "Medium" and the configured Medium delta is applied
Display Severity Badges and Confidence Adjustment
Given one or more data quality risks are present for any factor in the explanation When Why Match renders the factor explanations Then each affected factor shows a severity badge with label and color (Low=Gray, Medium=Amber, High=Red) within 500 ms of render start And a tooltip/popover reveals the reason code, evidence fields, and recommended next steps And the overall confidence recommendation displays per-risk deltas and a cumulative total with a trace of contributing risks And removing or resolving a risk updates badges and confidence totals within 1 second without a full page reload And badges and text meet WCAG AA contrast and are fully keyboard and screen-reader accessible
Audit Trail Link and Record Completeness
Given a match explanation includes at least one data quality risk When the user selects "View audit trail" from a risk detail Then the linked audit entry opens to the specific risk evaluation event within 1 second And the entry contains: risk type, reason code, severity, evidence payload references, confidence delta, evaluator version, input hashes, external lookup IDs, and an ISO-8601 timestamp And sensitive values are redacted (e.g., last-4, masked strings) according to policy And the record is immutable and includes a tamper-evident hash; any updates appear as new versions linked by correlation ID
Audit Trail Deep Link
"As a managing attorney, I want one-click access to the audit trail for a match so that I can defend our screening decision if challenged."
Description

Adds a permissioned deep link from every match explanation to the immutable audit log entry capturing inputs, algorithm version, factor weights, and decision outcomes. Each link includes a correlation ID and a cryptographic hash to ensure integrity and can be shared internally for review or exported for court filings. Respects role-based access controls, redacts sensitive PII when required, and records link access events for defensibility.

Acceptance Criteria
Open Audit Log from Match Explanation
Given an authenticated user with role 'Attorney' or 'Admin' and permission 'AuditTrail.View' And a match explanation panel is displayed for a specific match When the user clicks "View Audit Trail" Then the system opens the corresponding immutable audit log entry within 2 seconds at the 95th percentile And displays inputs, algorithm version, factor weights, decision outcome, correlation ID, and cryptographic hash And shows a "Verified" integrity status after recomputing and matching the hash And the correlation ID equals the match record's correlation ID And the algorithm version matches the version recorded for the match event
RBAC Enforcement on Audit Deep Link
Given a user is unauthenticated or lacks 'AuditTrail.View' When the deep link is accessed Then the system returns a 403 response with no PII and an access denied message And records a denied access event with timestamp, user (if known), IP, user-agent, correlation ID Given a user has 'AuditTrail.View' but lacks 'PII.ViewSensitive' When the deep link is accessed Then the audit entry loads with sensitive PII fields redacted according to policy And a redaction banner explains which categories were redacted and why And attempts to reveal redacted data are blocked and logged
Cryptographic Integrity Verification
Given an audit entry stores a canonical payload P and hash H (e.g., SHA-256) When the entry is opened via the deep link Then the system recomputes hash(P) and matches H And displays a "Verified" badge with the hash algorithm and verification timestamp When the recomputed hash does not match H Then the system displays an "Integrity check failed" alert And blocks export and sharing actions for this entry And emits a security alert event and records the failure in the audit trail
Internal Share of Permissioned Deep Link
Given an authorized user copies the audit deep link and shares it with a colleague When the colleague opens the link while authenticated and authorized Then the audit entry loads successfully and an access event is recorded with both the accessor and referrer (if available) When a user without required permissions opens the link Then the system returns 403 with no PII and logs the denial And the deep link URL contains only correlation ID and integrity parameters (no PII in query/path) And the link functions across supported browsers and devices
Export Audit Entry for Court Filing
Given an authorized user is viewing the audit entry When the user selects "Export" Then the system generates PDF and JSON exports within 5 seconds at the 95th percentile And the export includes inputs, algorithm version, factor weights, decision outcomes, correlation ID, cryptographic hash, and verification metadata And applies redaction rules per role and jurisdictional policy, with a redaction summary included And the export includes an access log summary for the entry And the exported files have deterministic filenames including correlation ID and UTC timestamp
Link Access Event Logging and Review
Given any access attempt to an audit entry via the deep link When the attempt occurs Then the system appends an immutable access event with timestamp, user ID (or anonymous), role, IP, user-agent, outcome (success/denied), correlation ID, and action (view/export) And Admin users can view the "Access History" within the audit entry UI sorted by most recent And access events are included in the export's access log section And events are write-once; any correction attempts are recorded as subsequent events referencing the original
Normalized Match Confidence
"As an attorney, I want a consistent confidence score across cases so that I can apply uniform decision thresholds regardless of data source or jurisdiction."
Description

Normalizes raw match scores from different data sources and jurisdictions to a consistent 0–100 confidence scale with configurable thresholds (Clear, Needs Review, Likely Conflict). Displays the mapping from factors to confidence, including any jurisdiction-specific adjustments, and allows admin tuning by practice area with change history. Provides shadow-mode analytics to compare tuned thresholds against historical outcomes without impacting current decisions.

Acceptance Criteria
Cross-Source Score Normalization to 0–100 Scale
- Given raw match scores from at least two providers on different scales, When normalization runs, Then each candidate displays a normalized confidence as an integer 0–100 inclusive using standard half-up rounding. - Given identical inputs, When normalization runs repeatedly, Then the normalized confidence is deterministic and identical across runs. - Given one source is unavailable or missing a score, When normalization runs, Then the normalized confidence is computed using configured fallback weights and the mapping flags "partial data" for the missing source. - Given jurisdiction-specific adjustment rules exist for the candidate’s jurisdiction, When normalization runs, Then the normalized confidence includes those adjustments and the mapping displays each applied adjustment with its signed delta and rule reference. - Given a normalized confidence is displayed in the UI, Then the API response for that candidate contains the same value and the same explanation keys (exact match).
Threshold Configuration: Clear / Needs Review / Likely Conflict
- Given an admin with permissions opens Thresholds for a practice area, When they set ReviewStart = R and LikelyStart = L and save, Then the system enforces 0 ≤ R < L ≤ 100 and blocks save otherwise with a specific inline error. - Then bands are assigned as: Clear = [0..R-1], Needs Review = [R..L-1], Likely Conflict = [L..100], and the UI labels correctly reflect the band for test scores R-1, R, L-1, L, and 100. - Given new thresholds are saved, When new matches are evaluated, Then banding uses the updated thresholds; historical stored decisions and labels are not altered. - Given an admin clicks Reset to Defaults, Then the practice-area defaults are restored, versioned, and become effective immediately for new evaluations. - Given a user without admin rights attempts to change thresholds, Then the action is denied and audited with user, timestamp, and practice area.
Explainable Mapping of Factors and Jurisdiction Adjustments
- Given a match result is opened, When the Why Match panel is viewed, Then it lists factor contributions (e.g., shared phone, alias similarity, cohabitation window, employer overlap) with individual weights and signed contributions that sum to the displayed normalized confidence (±1 due to rounding). - Given exact field matches exist, Then those fields are highlighted and labeled as exact with weight shown; fuzzy fields display similarity metrics (e.g., Jaro-Winkler 0–1) and associated weights. - Given jurisdiction-specific adjustments apply, Then each adjustment appears as a separate line item with rule name, citation/reference, and delta applied. - Given data quality risks are detected (e.g., recycled numbers), Then the panel flags the risk, shows its impact on confidence (delta or excluded), and links to documentation. - Given the user clicks "Audit Trail", Then the versioned configuration and rule set used for this score open in a new view from the exact evaluation timestamp.
Admin Tuning by Practice Area with Versioned Change History
- Given an admin edits factor weights or normalization parameters for a practice area, When they save, Then a new immutable version is created recording actor, UTC timestamp, before/after values, and optional comment (comment required if change >10% absolute on any weight). - Given a prior version is selected and "Revert" is clicked, Then the system creates a new version that restores those values without deleting history; the revert event is recorded. - Given non-admin users view tuning, Then values are read-only and clearly labeled as such. - Given change history is opened, Then versions are listed chronologically with diff highlights and can be exported to CSV including version ID/hash, actor, and change summary. - Given a new version is saved, Then evaluations created after the save use that version; evaluations created before retain the original version reference.
Shadow-Mode Analytics Against Historical Outcomes
- Given an admin defines a candidate tuning version and thresholds and selects a historical date range and practice area, When "Run Shadow Simulation" is started, Then live decisions/UI labels remain unchanged and a "Shadow Mode" badge is shown on the results. - Then the simulation computes and displays metrics including precision, recall, FPR, and a confusion matrix against labeled historical outcomes, plus deltas versus current production configuration. - Given up to 10,000 historical matches, Then the simulation completes within 2 minutes p95 and 4 minutes p99 with progress indicators; larger runs show ETA and allow cancel. - Given simulation results are viewed, Then the configuration version hash, thresholds used, and data selection criteria are displayed and exportable (CSV/JSON). - Given a simulation is canceled, Then no partial results modify any production configuration or labels and the cancel is logged.
Performance, Resilience, and Timeouts
- Given the normalization API is called for single-candidate evaluation, Then latency is ≤150 ms p95 and ≤300 ms p99 at 50 RPS per tenant over a 15-minute window, measured server-side. - Given batch evaluation of 100 candidates, Then completion time is ≤5 seconds p95 and ≤8 seconds p99 with identical results to single calls. - Given an upstream source exceeds 800 ms, Then the system applies a per-source timeout, proceeds with fallback weighting, and marks the source as "timeout" in the mapping. - Given transient errors occur, Then exponential backoff retries (max 2) are applied per source; persistent failures are surfaced as non-blocking warnings in the mapping and error logs include correlation IDs. - Given service health is degraded, Then circuit breakers prevent cascading failures and a status endpoint reflects dependency health with last-checked timestamps.
Auditability and Defensibility Exports
- Given a user views a match, When "Export Explanation" is clicked, Then a PDF is generated containing the normalized score, factor contributions, jurisdiction adjustments, thresholds in effect, configuration version hash, evaluator timestamp, and case identifiers. - Then the export includes a cryptographic signature or checksum and page-level footer with UTC timestamp and user ID. - Given a user with Auditor role signs in, Then they can access read-only audit trails for any case, including raw inputs used in scoring (as permitted), without the ability to modify configurations. - Given an audit trail is requested via API, Then the response includes immutable references (version IDs) and is retrievable for at least 7 years, configurable per tenant retention policy.
Explainability Export
"As a compliance officer, I want to export the explanation and evidence so that I can retain defensible records without exposing unnecessary PII."
Description

Exports the match explanation, highlighted fields, factor weights, and risk flags as a time-stamped PDF and machine-readable JSON for inclusion in e-filing packets and internal compliance records. Includes a legend of factors, user and system context, and chain-of-custody metadata. Applies role-based redaction and jurisdiction-specific masking rules to protect sensitive information while preserving defensibility.

Acceptance Criteria
Dual-Format Explainability Export
Given a permitted user (Attorney or Intake Admin) is viewing a Why Match explanation for a matter When they select "Export > Explainability" Then the system generates both a PDF and a JSON artifact within 5 seconds for a single match explanation with up to 50 matched fields And both artifacts are time-stamped in ISO 8601 UTC (Z) and their filenames follow CaseSpark_{MatterID}_{MatchID}_Explain_{YYYYMMDDThhmmssZ}.{pdf|json} And both artifacts include: plain-language match explanation, list of matched fields with highlight indicators, factor weights as numeric values in [0,1] with two decimal places, and risk flags with severity (Low|Medium|High) and code And the JSON validates against schema id "casespark.explainability.v1" with no errors And download links for both artifacts are presented immediately and remain valid for 7 days by default
Legend, Context, and Audit Trail Inclusion
Given an explainability export is generated Then the PDF contains a legend that defines each factor name, description, weight meaning, scoring scale, and highlight color key on the first or second page And both PDF and JSON include a context block with: userId, userRole, orgId, matterId, matchId, exportEventId (UUIDv4), appVersion, modelVersion, rulesetVersion, jurisdictionCode, createdAt (UTC), and sourceEnvironment And both artifacts include the auditTrailId and a deep link to the audit record; following the link as an authenticated user resolves within 1 second And both artifacts include a chain-of-custody section: sourceRecordHash (SHA-256), artifactHash (SHA-256), exporterId, exportReason, and signature metadata (algorithm and keyId)
Role-Based Redaction Policy Enforcement
Given a user with role Staff initiates an explainability export Then fields are masked in both PDF and JSON as: phone XXX-XXX-####, email first char + asterisks + domain (e.g., j*****@domain.com), SSN ***-**-####, street address line1 masked (city/state/ZIP retained), and minors’ names as first initial + last name Given a user with role Intake Admin initiates an export Then minors’ PII and third-party contact info are masked; other fields are unmasked Given a user with role Attorney initiates an export Then no role-based redaction is applied (only jurisdictional masking may apply) And every masked field includes redaction metadata {ruleId, role, reason, scope} in JSON and a visible redaction label in PDF And underlying unmasked values do not appear anywhere in the artifacts And attempts by users without Export permission are blocked with HTTP 403 and no artifacts are generated
Jurisdiction-Specific Masking Rules
Given matter jurisdiction = CA When an explainability export is generated Then DOB is masked to YYYY, SSN to last4, driverLicense to last3, child school is redacted, and all masking applies consistently in PDF and JSON Given matter jurisdiction = NY When an explainability export is generated Then DOB is masked to YYYY-MM, SSN to last4, and other adult contact details are unmasked unless role policy applies Given matter jurisdiction is Unspecified or Other Then default US policy applies: DOB YYYY-MM, SSN last4, minors’ PII masked And the applied jurisdictionCode and masking rulesetVersion are included in both artifacts And masking never hides which fields contributed to a match; if a matched field’s value is masked, the field name, a “masked” indicator, and its factor weight remain visible
Chain-of-Custody Integrity and Verification
Given an explainability export is generated Then both PDF and JSON include artifactHash (SHA-256) and sourceRecordHash (SHA-256) values And the export event is recorded in an immutable audit log with exportEventId, actor, timestamp (UTC), and IP (hashed) When the verification endpoint /exports/{exportEventId}/verify is called with the uploaded artifact Then it returns status "Pass" if the artifactHash matches and the signature metadata validates, otherwise returns "Fail" with mismatch details And retrieving the export later yields artifacts whose hashes are identical to those recorded at export time
E-filing Compatibility and Accessibility
Given an explainability export is generated Then the PDF conforms to PDF/A-2b, includes selectable text, bookmarks, and tagged structure, and passes the internal PDF/A validator with no errors And highlight colors meet WCAG 2.1 AA contrast and reading order is correct for screen readers And the JSON size is <= 10 MB and includes top-level keys: meta, context, explanation, factors, matchedFields, riskFlags; arrays are present even if empty When the artifacts are packaged by the internal e-filing assembler Then the PDF is accepted without conversion and the JSON attaches as a machine-readable exhibit with no validation errors

Attest & Learn

Clears false positives with reason codes (e.g., common name, wrong person, prior roommate) that are logged for compliance and used to suppress repeat noise. Optional reviewer routing and expiry dates keep controls tight, while adaptive learning refines future matches without hiding genuine risk.

Requirements

Reason Code Library & Policy Controls
"As a conflicts analyst, I want to choose standardized reason codes with required notes and evidence so that clearances are consistent and audit-ready across the firm."
Description

Centralized, versioned catalog of standardized false-positive reason codes (e.g., common name, wrong person, prior roommate) with firm- and jurisdiction-level configuration. Admins can add, deprecate, and map codes to policies, require mandatory fields (notes, evidence, data source), and localize labels. Enforces consistency across CaseSpark’s conflict screening UI and APIs, supports evidence attachments, and stores metadata for compliance (actor, timestamp, source system). Includes validation rules, change history, and permissions to prevent unauthorized edits.

Acceptance Criteria
Admin creates a new reason code with versioning and validation
Given I am an Admin of Firm A and authenticated in CaseSpark When I create a reason code with key "COMMON_NAME", default label "Common name", description, and map it to policy IDs ["POL-001"] Then the code is saved as version "1.0", active status, and visible in the Reason Code Library And the API GET /reason-codes returns the new code with version "1.0", policyIds ["POL-001"], createdBy, createdAt, and sourceSystem And attempting to create another code with key "COMMON_NAME" in Firm A fails with 409 and a uniqueness error And omitting required fields (key, default label) results in 422 with field-level error messages
Policy-enforced mandatory fields when applying a reason code (UI and API)
Given Firm A policy for "WRONG_PERSON" requires notes and at least one evidence attachment and a data source value When a reviewer in the UI selects "WRONG_PERSON" without notes, attachment, or data source and clicks Submit Then the submission is blocked and inline errors specify missing "notes", "evidence", and "dataSource" When the same payload is sent to POST /attestations via API without the required fields Then the API responds 422 with errors for "notes", "evidence", and "dataSource" When notes (>=10 chars), one allowed attachment, and data source "Client Call" are provided Then the attestation saves successfully in UI and API, and the record stores notes, evidenceId(s), dataSource, actor, timestamp, and sourceSystem
Jurisdiction-level configuration and inheritance
Given Firm A sets firm-level defaults requiring "notes" for all codes And sets a jurisdiction override for "CA" requiring "notes" and "evidence" for "COMMON_NAME" When an attestation for a case in jurisdiction "CA" uses "COMMON_NAME" Then validation requires both "notes" and "evidence" When an attestation for jurisdiction "NY" uses "COMMON_NAME" Then only "notes" is required When jurisdiction is unknown Then firm-level defaults are applied
Deprecating a reason code with safe rollout
Given code "PRIOR_ROOMMATE" version "1.2" is active When an Admin deprecates it effective immediately with a deprecation note Then the code status becomes "Deprecated" and change history logs actor, timestamp, note, and fromStatus->toStatus And the code no longer appears in selection lists in UI for new attestations And GET /reason-codes excludes it by default, but includes it when includeDeprecated=true And attempts to use "PRIOR_ROOMMATE" in new attestations (UI or API) fail with 422 and errorCode "CODE_DEPRECATED" And existing historical attestations referencing "PRIOR_ROOMMATE" remain readable
Evidence attachment handling and compliance metadata
Given firm policy requires evidence for "WRONG_PERSON" When a reviewer uploads an attachment of type PDF, JPG, or PNG up to 25 MB Then the file is virus-scanned, stored, and linked by stable evidenceId, with a checksum and contentType recorded And uploads of disallowed types or oversized files are rejected with specific error messages And the attestation record stores evidenceId(s), actor, timestamp, and sourceSystem
Localized labels and API/UI language negotiation
Given "COMMON_NAME" has default label "Common name" and a Spanish label "Nombre común" When a user with locale es-ES views the code in UI Then the Spanish label "Nombre común" is displayed When the API GET /reason-codes is called with Accept-Language: es-ES Then the response returns label "Nombre común" and locale "es-ES" When a translation is missing for a requested locale Then the default label is returned and displayed When an Admin updates the es-ES label Then the change is versioned and logged in history with actor, timestamp, and before/after values
Permissions and audit trail for library changes
Given roles are configured such that only "Admin" may create, edit, or deprecate reason codes When a non-Admin attempts to create or edit a reason code via UI or API Then the action is blocked with 403 Forbidden and an audit event is recorded with actor, attempted action, timestamp, and sourceSystem When an Admin makes any change (create, edit, deprecate) Then change history records actor, timestamp, sourceSystem, before/after values, version increment, and related policy mappings And the history is viewable with filters by date range, actor, code key, and action
Attestation Workflow & Immutable Audit Trail
"As a staff attorney, I want to attest to a clearance with a signed statement so that the firm maintains defensible, tamper-evident records for regulators and clients."
Description

Structured attestation step when clearing a potential conflict: capture attestor identity, statement, timestamp, IP/device, and optional e-sign affirmation. Generates an immutable, append-only audit record with hash chaining to detect tampering. Accessible via matter timeline and exportable for regulators. Integrates with CaseSpark intake so a matter cannot proceed to filing if attestation is incomplete where policy requires it. Supports comment threads and links to source matches and reason codes.

Acceptance Criteria
Attestation Capture Completeness
- Given a potential conflict is being cleared in CaseSpark intake When the user opens the attestation step Then the form requires and records attestor identity (user ID or full name), free-text statement (min 10 characters), timestamp with timezone, public IP address, and device fingerprint - Given e-sign is required by policy When the attestor submits Then a validated e-sign event with signer identity, signature hash/image, provider transaction ID, and timestamp is attached and stored - Given any required field is missing or invalid When submit is clicked Then submission is blocked with inline error messages and no audit record is written - Given submission succeeds When viewing the attestation entry Then all captured fields display read-only and match stored values
Immutable Audit Trail with Hash Chaining
- Given an attestation event is written When it is appended to the audit log Then the record includes its SHA-256 hash, the previous record's hash, a monotonically increasing sequence number, and a created-at timestamp - Given any existing audit record is modified outside the application When the integrity check job runs Then a hash mismatch is detected, the matter timeline shows "Tamper suspected", and a security event is emitted - Given multiple attestations exist for a matter When retrieving the chain Then the chain is contiguous with no missing sequence numbers and validates end-to-end within 100 ms per 1,000 records - Given a verification endpoint is called with a matter ID When the chain is fetched Then it returns ordered records with per-record hashes and an overall chain verification status of Pass or Fail
Matter Timeline Visibility and Regulator Export
- Given a matter with at least one attestation When viewing the matter timeline Then each attestation appears as a distinct, timestamped entry with attestor identity, statement preview, selected reason codes, and links to source matches - Given a user with Export permissions When exporting the attestation audit Then the system produces a bundle within 5 seconds containing PDF, CSV, and JSON files with full attestation fields, hash chain data, and comment threads - Given an export bundle is generated When opened Then the PDF includes a chain verification summary and the JSON includes per-record hash and prev_hash values - Given access controls When a user without Export permissions attempts export Then the request is denied with HTTP 403 and no data is returned
Intake Gatekeeping Based on Attestation Policy
- Given firm policy requires attestation for conflict clearances When a potential conflict is marked "Clear" without a completed attestation Then the "Proceed to Filing" action is disabled in the UI and the API returns 409 Conflict with error code ATT-REQUIRED - Given a completed, valid attestation exists for the current conflict instance When attempting to proceed to filing Then the action succeeds and the audit log records the policy check outcome - Given policy is conditional (e.g., only for high-risk matches) When the condition is not met Then proceeding to filing is not blocked by attestation requirements
Reason Codes, Source Match Linking, and Comments
- Given a conflict result is being cleared When attesting Then the user must select one or more predefined reason codes or an admin-allowed custom code, and the attestation stores normalized reason_code IDs - Given the attestation references screening results When viewing the attestation Then each linked match displays provider, match ID, score, entity names, and a link back to the original results - Given collaborators add comments When posting to the attestation thread Then each comment stores author and timestamp, is append-only, and edits are recorded as new events in the audit chain - Given an export is generated When reviewed Then comments and reason codes are included and searchable
Reviewer Routing and Attestation Expiry
- Given policy requires reviewer approval When an attestation is submitted Then it enters the reviewer queue with status Pending Review and notifications are sent to designated reviewers within 60 seconds - Given a reviewer opens the attestation When approving or rejecting Then the action is recorded as an audit event with reviewer identity, timestamp, decision, and optional note; rejection re-opens the attestation for edits - Given an expiry period is configured (e.g., 90 days) When the expiry date passes Then the attestation is marked Expired, proceeding to filing is blocked, and re-attestation is required - Given re-attestation occurs after expiry When completed Then the new attestation references the prior one and the hash chain remains contiguous
E-Sign Affirmation Option and Evidence
- Given e-sign affirmation is enabled When the attestor signs Then the system captures signer name, email, IP, timestamp, signature hash, e-sign provider certificate/transaction ID, and stores a tamper-evident copy of the signed affirmation - Given e-sign is disabled by policy When the attestor submits Then no signature is requested and all non-e-sign attestation fields are recorded - Given a regulator requests evidence When exporting Then the export bundle includes the e-sign certificate or equivalent audit artifact linked to the attestation - Given the e-sign provider webhook is delayed or fails When submission occurs Then the attestation is marked Awaiting Signature Confirmation and the system retries verification for up to 24 hours before failing with a clear error state
Reviewer Routing & Dual-Control
"As a managing partner, I want higher-risk clearances to be routed to an approver so that no one can self-clear sensitive conflicts and we meet firm policy."
Description

Configurable rules engine that routes certain clearances to designated reviewers based on risk factors (match score, shared address, same last name, VIP client, jurisdiction) and firm policy. Supports dual-control (preparer vs. approver), prevention of self-approval, SLAs, reminders, escalation paths, and vacation delegations. Presents a review queue in CaseSpark, adds outcomes to the audit trail, and blocks downstream document assembly until approval is granted.

Acceptance Criteria
Deterministic Reviewer Routing by Risk and Policy
Given routing rules exist for match score ≥ 0.85, shared address, same last name, VIP client, and jurisdiction FamilyCourtX, and a default reviewer group is configured When a clearance with match score 0.90 and same last name is submitted by a preparer Then the item is routed to the designated reviewer per the highest-priority matching rule, appears only in that reviewer’s queue within 10 seconds, and the audit trail records the matched rule ID, timestamp, and assignee And if multiple rules match, the highest-priority rule is applied; ties resolve to the most specific rule; otherwise the default reviewer group is used And no other reviewer receives the item unless re-assigned by escalation or delegation
Dual-Control and Self-Approval Prevention
Given user A prepared the clearance and firm policy requires dual-control (separate preparer and approver) When user A attempts to approve or clear the item via UI or API Then the action is blocked with message "Self-approval is not permitted", no status change occurs, and the attempt is logged When user B with Approver role approves the item Then the status updates to Approved, the approver is recorded as user B, and the audit trail captures preparer, approver, and timestamp
SLA Timers, Reminders, and Escalation
Given an SLA of 4 business hours with reminder at 2 hours and escalation to Tier 2 at 4 hours is configured; business hours Mon–Fri 09:00–17:00 excluding firm holidays When an item is assigned at 10:00 on a business day and remains unacted Then a reminder notification is sent to the assignee at 12:00 with delivery logged And at 14:00 the item auto-escalates to Tier 2, the original assignee is notified, and audit entries are created for reminder and escalation And SLA timers pause outside business hours and resume next business day
Vacation Delegation of Review Responsibilities
Given Reviewer C has an active vacation delegation from 2025-09-15 through 2025-09-22 to Delegate D When items are routed to Reviewer C during that window Then items are assigned to Delegate D’s queue within 10 seconds, both C and D receive notifications, and the delegation is recorded in the audit trail And items routed before the window remain with Reviewer C unless escalated or manually reassigned And after 2025-09-22 23:59 local time, routing reverts automatically to Reviewer C
Block Document Assembly Until Approval
Given a matter’s conflict clearance status is Pending Review or Denied When any user or integration attempts to initiate document assembly for that matter Then the action is blocked with message "Document assembly is locked until clearance approval", API calls receive HTTP 409, and no documents are generated When the clearance status becomes Approved Then document assembly can be initiated successfully without block
Comprehensive Audit Trail for Review Events
Given audit logging is enabled by default When routing, reassignment, approval/denial, reminder, escalation, delegation, or block events occur Then each event is logged immutably with timestamp (UTC), actor (user or system), event type, matched rule ID (if any), prior and new assignee, decision, reason code (if provided), and SLA checkpoints And audit records are viewable in the matter timeline and exportable as CSV and JSON with verified checksums
Reviewer Queue Visibility and Controls
Given a reviewer has one or more assigned items When viewing the review queue Then each item displays client/matter name, match score, risk flags (shared address, same last name, VIP), jurisdiction, received time, time remaining to SLA breach, and current status And the reviewer can sort by SLA time remaining, match score, and received time; filter by risk flags and jurisdiction; and take Approve, Deny, Request Info actions inline And the queue view loads within 2 seconds for up to 200 items and supports keyboard navigation with accessible labels (WCAG 2.1 AA)
Expiry & Revalidation Engine
"As an operations manager, I want clearances to expire and trigger re-checks so that stale decisions don’t hide new risks as facts change."
Description

Allows setting expiry durations per reason code, risk level, matter type, and jurisdiction. Schedules automatic revalidation checks and notifications before expiry, re-runs conflict screening with fresh data, and prompts users to re-attest or escalate. If a clearance expires without revalidation, suppressions are lifted and the matter is paused before filing. All revalidation outcomes are linked to the original audit chain.

Acceptance Criteria
Configurable Expiry by Reason, Risk, Matter, Jurisdiction
Given I am an admin with permissions to manage conflict revalidation settings, When I set expiry durations per reason code, risk level, matter type, and jurisdiction and click Save, Then the system validates durations are integers between 1 and 1095 days and saves a versioned configuration with an effective timestamp. Given overlapping rules exist (e.g., a general reason code rule and a reason+jurisdiction rule), When the system evaluates an attestation’s expiry, Then the most specific applicable rule takes precedence following specificity order: reason+risk+matter+jurisdiction > reason+risk+jurisdiction > reason+jurisdiction > reason > default. Given no specific rule applies, When the system evaluates an attestation’s expiry, Then the global default duration is applied and recorded. Given timezones differ across users, When an expiry is computed, Then the expiry is stored and displayed in UTC with localized rendering in the UI.
Pre-Expiry Notifications and Reminders
Given a clearance has an expiry date, When it is T-14, T-7, and T-1 days before expiry, Then the system schedules and sends notifications via in-app and email to the matter owner and designated reviewer containing matter ID, parties, reason code, expiry timestamp, and a link to revalidate. Given an email delivery failure occurs, When a notification send attempt fails, Then the system retries up to 3 times with exponential backoff and records delivery status and error details in the audit log. Given user notification preferences exist, When reminders are sent, Then channel selection respects user preferences while always recording an in-app alert. Given a notification is delivered, When the user clicks the link, Then they are taken directly to the revalidation task for that clearance with SSO-authenticated deep-linking.
Automated Revalidation Screening with Fresh Data
Given a clearance is within the revalidation window, When the scheduled revalidation job runs, Then the system re-runs conflict screening against all configured data sources using the latest available data as of job start time and records source data snapshot IDs. Given suppressions exist from the prior clearance, When revalidation runs, Then the screening evaluates matches without applying prior suppressions for assessment purposes while leaving live suppressions unchanged until re-attestation completes. Given external data sources have outages, When revalidation runs, Then the job marks the run as partial, queues a retry within 2 hours, and notifies the owner if freshness SLAs cannot be met by expiry. Given revalidation completes, When results are available, Then a diff is generated comparing prior and current matches including added, removed, and severity-changed items.
User Re-Attestation and Escalation Workflow
Given revalidation results are ready, When the owner reviews and confirms that prior reason codes still apply, Then they can re-attest by selecting the applicable reason codes, providing required notes, and the system extends the expiry per current configuration. Given a new higher-risk match is detected or policy requires reviewer approval for this risk tier, When the owner attempts to re-attest, Then the system routes the task to the designated reviewer queue with the appropriate SLA and blocks auto-extension until reviewer approval. Given reviewer approval is granted, When the reviewer approves with a reason code, Then the expiry is extended, suppressions updated, and the reviewer’s decision is captured in the audit trail. Given reviewer rejection occurs, When the reviewer rejects, Then the matter is auto-paused, stakeholders are notified, and escalation options are presented.
Lapse Handling: Lift Suppressions and Pause Before Filing
Given a clearance reaches expiry with no completed revalidation, When the expiry timestamp passes, Then all suppressions tied to that clearance are lifted for active screening, the matter status changes to Paused - Revalidation Required, and filing actions are blocked. Given filing is attempted on a paused matter, When a user tries to file, Then the system prevents filing and displays a banner with the reason and a CTA to complete revalidation. Given suppressions are lifted due to lapse, When a new conflict is now visible, Then it appears in conflict lists and triggers standard conflict alerts.
Audit Chain Integrity and Traceability
Given a clearance has revalidations over time, When any revalidation action occurs (auto run, re-attest, reviewer decision, lapse), Then the event is appended to the original clearance’s immutable audit chain with timestamps, actor, role, IP, configuration version, and result. Given auditors need to review history, When the audit chain is retrieved via UI or API, Then all links show a complete, ordered lineage from initial clearance to latest outcome, including references to the screening snapshots used. Given data retention policies, When records reach retention thresholds, Then redaction/anonymization occurs without breaking referential integrity of the audit chain.
Adaptive Learning Noise Reduction with Safeguards
Given multiple re-attestations with the same entity pair and reason code occur (e.g., ≥3 within 180 days) and all were approved, When a future identical match is encountered, Then the system auto-suggests suppression with a learning reason and sets an expiry per configuration without auto-hiding the match until the user confirms. Given a learned suppression candidate exists, When the current match severity exceeds the configured risk threshold or new risk attributes are present, Then the system does not suggest auto-suppression and flags the change for reviewer attention. Given a user accepts or rejects a learning suggestion, When the action is taken, Then the learning model updates counts and confidence, logs the decision, and adjusts future suggestion likelihoods without lowering detection thresholds.
Suppression with Safety Nets
"As an intake specialist, I want previously cleared false positives to stay out of my queue unless something meaningfully changes so that I can process new matters faster without missing real risk."
Description

Suppresses repeat false-positive matches by generating stable suppression keys from normalized party identifiers, aliases, and context (jurisdiction, matter type). Applies reason-code-specific suppression windows and scopes, while automatically resurfacing matches when material attributes change (party DOB, address, new adverse party) or when external risk signals increase. Provides a suppression management view with search, bulk actions, and one-click unsuppress.

Acceptance Criteria
Stable Suppression Key Generation Across Aliases and Contexts
Given a party with multiple aliases and normalized identifiers (name, DOB, address) in jurisdiction=J1 and matter_type=M1 When conflict screening runs and a suppression is created with a reason code Then the generated suppression key is deterministic and identical across repeated runs for the same normalized identifiers within J1+M1 Given the same party is screened in a different jurisdiction or matter type When the suppression key is generated Then the key differs, establishing a distinct suppression scope Given two different individuals share a common name but differ by DOB or address When suppression keys are generated Then the keys are different and do not collide Given a future false-positive match maps to an existing suppression key within its active window and scope When screening runs Then the match is auto-suppressed and linked to the existing suppression entry
Reason-Code Windows and Scopes Applied and Enforced
Given admin configuration defines suppression windows and scopes per reason code (e.g., Common Name=90 days, scope=party; Wrong Person=180 days, scope=party+adverse) When a user suppresses a match with a selected reason code Then the system sets the expiry to the configured window and applies suppression only within the configured scope Given time is within the active window When an identical match occurs within scope Then it is suppressed automatically Given the window is expired When screening runs Then the match surfaces again Given a match occurs outside the configured scope (e.g., different adverse party when scope includes adverse) When screening runs Then the match surfaces despite an active suppression
Automatic Resurfacing on Material Attribute Change or Risk Increase
Given a match is suppressed for a party When the party's DOB or primary address is updated Then the prior suppression is invalidated for that party and the match resurfaces on the next screening run (or within 60 seconds in continuous monitoring) Given a new adverse party is added to the matter When suppression scope includes adverse party Then the suppression no longer applies and related matches resurface on next screening Given an external risk signal for the matched entity crosses the configured override threshold When monitoring is active Then the match surfaces immediately with an override indicator despite active suppression
Suppression Management View: Search, Bulk Actions, One-Click Unsuppress
Given a user with Manage Suppressions permission When they open Suppression Management Then they can filter by party name, suppression key, reason code, jurisdiction, matter type, created_by, created_at range, and expires_at range Given one or more suppressions are selected When the user performs Bulk Unsuppress Then all selected entries are unsuppressed, audit events are recorded, and affected matches will surface on next screening Given a single suppression is viewed When One-Click Unsuppress is invoked Then the suppression is removed immediately and confirmation is shown Given an export is requested for current filters When the export completes Then a CSV is downloaded containing id, key, reason_code, scope, window_days, created_by, created_at, expires_at, party identifiers, adverse parties, jurisdiction, matter_type, and notes Given a user without permission attempts access When they navigate to Suppression Management Then access is denied
Reviewer Routing and Approval Workflow for Suppressions
Given reviewer routing is enabled When a user submits a suppression request with a reason code and justification Then a review task is created and suppression remains pending until approved Given a reviewer approves within SLA When approval is recorded Then the suppression becomes active with configured window and scope, and notifications are sent to requester Given a reviewer rejects When rejection is recorded Then no suppression is applied and the match remains surfaced with rejection reason visible Given SLA (e.g., 24 hours) passes with no action When the deadline is reached Then reminders are sent to reviewer and requester and the task remains pending
Immutable Audit Logging and Compliance Export
Given any suppression create, update (including scope/window changes), approval/rejection, or unsuppress action When the action is saved Then an immutable audit record is written including timestamp, actor, action, reason_code, justification text, scope, window_days, suppression key, source match identifiers, before/after values, reviewer info (if applicable), and request origin (UI/API) Given a compliance export is requested for a date range When the export is generated Then a complete, chronologically ordered report is produced in CSV and JSON matching the audit records for that range Given a user views a suppression's history When the History panel is opened Then all audit events for that suppression are displayed in reverse chronological order with full details
Adaptive Learning Feedback Loop
"As a product admin, I want the system to learn from our clearances and tune matching so that we see fewer false positives while still catching true conflicts."
Description

Feeds cleared and confirmed matches into a learning layer that adjusts matching thresholds, name normalization, and weighting of features (e.g., address proximity, prior roommate relationships) per jurisdiction and practice area. Runs in shadow mode first with evaluation metrics to prevent recall loss, provides explainable deltas, and supports rollback. Integrates with suppression logic to reduce noise without hiding genuine conflicts.

Acceptance Criteria
Shadow Mode Evaluation Protects Recall
Given a baseline model version v_base and a candidate learning layer v_cand running in shadow mode across all new intakes for 14 consecutive days with at least 500 screened subjects per jurisdiction When evaluation is run on a held-out labeled set with ≥200 true conflicts and ≥1,000 non-conflicts per jurisdiction–practice area Then recall(v_cand) − recall(v_base) ≥ −0.005 and precision(v_cand) ≥ precision(v_base), or F1(v_cand) ≥ F1(v_base) And promotion is automatically blocked and an alert emitted if any guardrail is violated And a dashboard displays per-jurisdiction precision, recall, F1, FP rate, TP count with 95% confidence intervals
Jurisdiction- and Practice-Area-Specific Threshold Tuning
Given ≥100 labeled cleared false positives and ≥50 confirmed true conflicts per jurisdiction–practice area collected in the last 90 days When the learning layer updates matching thresholds, name normalization rules, and feature weights Then distinct, versioned parameter sets are produced per jurisdiction and practice area with effective dates And offline evaluation shows ≥20% reduction in false positives at equal or improved recall (Δrecall ≥ 0), or ≥30% FP reduction with recall loss ≤0.5 percentage points And deployment requires explicit approver sign-off recorded in an immutable audit log
Explainable Deltas for Model Changes
Given a proposed parameter update v_cand compared to v_base When a change report is generated Then the report lists threshold deltas, top-10 feature weight changes with importance deltas, reason-code mapping changes, and predicted metric impact per jurisdiction–practice area And the report includes at least 3 representative example cases per major change category And the report is exportable to PDF and JSON and attached to the model version record And each screening decision view displays why the score changed vs prior version using reason codes and weight contributions
Rollback to Prior Model State
Given a model version v_new has been promoted within the last 30 days When an administrator triggers rollback to v_prev Then the system reverts within 5 minutes with no request loss; in-flight evaluations complete under v_prev And a 1,000-record verification sample matches v_prev outputs bit-for-bit And audit logs capture rollback request, actor, timestamps, target version, and rationale
Suppression Logic Integration Without Masking True Conflicts
Given a cleared hit with reason code "Common Name" and a suppression expiry of 90 days When the same entity pattern reappears within 90 days without new corroborating signals Then the hit is hidden from the default review queue, counted in suppression metrics, and retrievable via a "Suppressed" filter And any corroborating risk signal (e.g., exact DOB+SSN match, direct party relationship) overrides suppression and surfaces the hit And a quarterly backtest against a gold-standard set shows 0 suppressed true positives and ≥25% reduction in review queue volume attributable to suppression
Reviewer Feedback Ingestion Drives Learning
Given a reviewer marks a match as "Cleared" with a reason code or "Confirmed Conflict" When the feedback is submitted Then the event is stored immutably with actor, timestamp, jurisdiction, practice area, and evidence references And after automated QA (deduplication, data quality checks, required PII masking), the labeled record is available to the training pipeline within 24 hours And records from opt-out jurisdictions are excluded from training per policy and logged And a monitoring dashboard displays weekly counts of ingested labels, data freshness, and their inclusion in the next training run

Instant Guard

Runs live conflict scans as intake is being completed, flagging potential issues before sensitive data is collected. Prompts callers for lightweight disambiguation (middle name, birth month, last‑4 phone) to confirm identity on the spot, and auto‑halts engagement steps via Stage Gates when a high‑risk hit appears.

Requirements

Real-Time Conflict Scan Engine
"As an intake specialist, I want conflicts checked instantly as I capture caller details so that I can catch and address issues before collecting sensitive information."
Description

Continuously evaluates intake data as it is entered and performs low-latency conflict scans against internal client/matter records and connected third-party datasets. Supports fuzzy matching, nicknames, phonetic algorithms, transliteration, and typo tolerance to surface probable matches with confidence scores and match rationale. Targets p95 response under 800 ms per incremental scan with graceful degradation to queued checks when services are unavailable. Integrates with CaseSpark’s intake event stream to trigger scans on field change, deduplicates results, and exposes structured findings for downstream gating and alerts. Implements timeouts, retries with exponential backoff, and circuit breaking to maintain responsiveness.

Acceptance Criteria
Incremental Scan Performance on Field Change
Given an intake field-change event for a party name or contact field When the Real-Time Conflict Scan Engine runs an incremental scan Then the 95th percentile end-to-end latency measured over the most recent 1,000 scans is less than or equal to 800 ms And the response for the event includes either structured findings or an explicit no_matches result
Fuzzy Matching, Nicknames, Phonetics, Transliteration, and Typo Tolerance
Given a test corpus containing known nickname pairs, phonetic variants, transliterated forms, and names with up to two single-character typos When the engine performs a conflict scan Then probable matches for each variant type are returned And each match includes a confidence score on a 0.0–1.0 scale and a human-readable match rationale specifying matched fields and algorithms used
Result Deduplication Across Sources and Repeated Scans
Given multiple data sources return the same real-world person across different identifiers during an intake session When the engine aggregates scan results Then findings are deduplicated to a single entry per unique entity within the scan session And each deduplicated finding lists all contributing dataset identifiers and source record keys
Graceful Degradation to Queued Checks on Service Unavailability
Given a connected third-party dataset is unavailable or exceeds its per-request timeout When an incremental scan is triggered Then partial findings from available sources are returned within 800 ms And deferred checks are enqueued with exponential backoff and status queued with correlation to the originating intake event And upon service recovery, queued checks execute and their findings are emitted with the original correlation identifier
Timeouts, Retries, and Circuit Breaking Maintain Responsiveness
Given a data source request exceeds the configured timeout When the engine retries the request Then it performs up to 3 retry attempts using exponential backoff with jitter And the circuit breaker for that source opens after 5 consecutive failures within 60 seconds and remains open for 120 seconds before half-open probes And while the circuit is open, the engine skips live calls to that source and immediately enqueues queued checks
Structured Findings for Downstream Gating and Alerts
Given the engine produces one or more matches When findings are emitted Then each finding is a JSON object containing at minimum: correlation_id, entity_id, source_datasets, matched_fields, algorithms_used, confidence (0.0–1.0), rationale, timestamp_ms, scan_kind (incremental or full), and dedup_key And the emitted payload validates against the published JSON Schema ConflictFinding.v1
Adaptive Disambiguation Prompts
"As a caller, I want simple follow-up questions that confirm my identity so that the firm can resolve potential conflicts without asking for unnecessary personal data."
Description

When a probable conflict match is found, dynamically prompts the caller for lightweight disambiguation data (e.g., middle name, birth month, last 4 digits of phone) chosen based on gaps in already-captured information and match characteristics. Provides accessible, locale-aware phrasing across voice and web workflows, supports skip/unknown responses, and limits collection to the minimum necessary data. Responses are stored ephemerally until conflict clearance, then either persisted per policy or discarded. Exposes a deterministic prompt-selection logic and a fallback path to manual verification when confidence cannot be resolved within a set number of prompts.

Acceptance Criteria
Dynamic Prompt Selection and Minimum Necessary Data
Given an intake session with a probable conflict match and previously captured fields And a configured prompt inventory with allowed data elements {middle_name, birth_month, last4_phone, zip5, city} and priority weights When the system selects a disambiguation prompt Then it selects only prompts for data elements not already captured And it requests no more than one data element per prompt And it never selects prompts outside the allowed minimal set And the selection is deterministic for identical inputs And the chosen prompt maximizes configured discriminative score And the flow issues no more than N prompts (default 3; configurable) And the decision is logged with prompt_id, reason_code, candidate_count, and timestamp
Confidence Resolution and Prompt Termination
Given a configured confidence threshold T (default 0.95) And a maximum prompt count N (default 3) When a caller response is applied to the match model Then confidence_before and confidence_after are recorded And if confidence_after >= T, the system stops presenting further prompts immediately And it will not request the same data element again in this session And if after N prompts confidence_after < T, the system marks the session unresolved and triggers the fallback event
Skip/Unknown Response Handling
Given a disambiguation prompt is presented When the caller selects Skip or Unknown Then the response is recorded with null_reason in {skipped, unknown} And the system treats the value as missing for subsequent selection And the attempt counts toward N prompts And the flow advances without an error state And if all remaining eligible prompts would request already-captured or disallowed data, the system triggers the fallback event
Locale- and Channel-Appropriate Prompting (Web and Voice)
Given locale L and channel C in {web, voice} When rendering a disambiguation prompt Then localized phrasing for L is used; if unavailable, fallback to en-US neutral phrasing And for web: labels/help/error comply with WCAG 2.2 AA and are keyboard-accessible And for voice: TTS prompt provided, ASR grammar accepts expected variants, and a DTMF alternative is available And English prompts meet <= 8th-grade reading level (Flesch–Kincaid) And each prompt includes a brief purpose statement describing minimal data use
Ephemeral Storage and Post-Decision Data Handling
Given disambiguation responses are collected during an unresolved session When the conflict outcome is set to Cleared Then responses are persisted only if persist_disambiguation=true (policy); otherwise values are deleted within 60 seconds When the outcome is Conflict or fallback is triggered Then response values are deleted within 60 seconds and only metadata (prompt_id, timestamps, reason_codes) remains in audit logs And while unresolved, values are stored in encrypted ephemeral storage with TTL 30 minutes; on TTL expiry without outcome, auto-delete values and trigger fallback And deletions are irreversible and evidenced by audit events
Deterministic Logic Exposure and Traceability API
Given a prompt selection or confidence evaluation occurs When a privileged user/system requests the decision trace Then the API returns logic_version, inputs_snapshot (redacted), candidate_scores, selected_prompt_id, reason_codes, thresholds, and timestamps And two requests with identical inputs_snapshot produce identical selected_prompt_id and candidate_scores And access is role-restricted, audited, and P95 response time is <= 300 ms
Manual Verification Fallback and Stage Gate Enforcement
Given confidence remains below T after N prompts or a high-risk hit is detected When this condition is met Then the system sets Stage Gate = Conflict Verification Required, halts downstream engagement steps, and stops further PII prompts And it creates a manual verification task with context (candidate list, collected minimal data, trace link) And it notifies assigned staff via configured channel within 60 seconds And upon authorized resolution (override, confirm conflict, or clear), the Stage Gate is updated and the intake flow resumes accordingly And all transitions are timestamped and auditable
Stage Gate Enforcement
"As a managing attorney, I want the system to stop engagement actions when a conflict is flagged so that we never onboard a conflicted client by mistake."
Description

Automatically halts downstream engagement steps (retainer generation, e-sign, payment collection, scheduling, and document assembly) when a high-risk or unresolved conflict is detected. Presents resolution options (decline, obtain informed consent, ethical screen, or attorney review) and requires authenticated authorization to proceed. Gates are enforced across UI and API surfaces to prevent bypass, with configurable thresholds and timeouts that auto-cancel stalled intakes. Provides user-facing explanations and links to firm policy so staff can act consistently.

Acceptance Criteria
Gate Triggers on High-Risk Conflict During Intake
Given an intake with a conflict scan result where risk_score >= firm.gate_risk_threshold OR conflict_status in {HighRisk, Unresolved} When the stage gate evaluator processes the latest scan update Then intake.stage_gate_state is set to "Gated" within 1 second and gate_reason is recorded And all downstream engagement actions are marked unavailable across UI and API And an audit entry "StageGateActivated" is created with actor_id (if any), risk_score, conflict_ids, and timestamp
UI Enforcement Blocks All Downstream Engagement Steps
Given an intake with stage_gate_state = "Gated" When a user opens any engagement action in the UI Then retainer generation, e‑sign initiation, payment collection, scheduling, and document assembly controls are disabled and visually indicated as blocked And attempts to deep-link to those pages redirect to the intake view with a non-dismissible gate banner And any forms that collect PII or payment data are not rendered while the gate is active And controls remain blocked after refresh, new session, or device change (server-validated)
API Enforcement Prevents Bypass of Engagement Endpoints
Given an intake with stage_gate_state = "Gated" When a client calls POST endpoints for /retainers, /esign, /payments, /scheduling, or /documents for that intake Then the API responds 423 Locked with error.code = "STAGE_GATE_BLOCKED", including intake_id, gate_reason, and remediation_actions And no side-effects are performed (no records created, no external calls) And this behavior is enforced for both user tokens and service-to-service tokens And an audit entry "StageGateBlockedAttempt" is recorded with endpoint, actor, and timestamp
Resolution Options Require Authorized Approval to Proceed
Given an intake with stage_gate_state = "Gated" When a user selects Resolve Gate Then options presented are: Decline Matter, Obtain Informed Consent, Apply Ethical Screen, Request Attorney Review And confirming any option requires an authenticated user with role in {Attorney, ManagingAttorney} and a required reason note And Obtain Informed Consent requires captured/attached consent artifacts and (when applicable) consent from all required parties before proceeding And Apply Ethical Screen requires selecting screened users and verifying screen configuration is active And upon successful authorized resolution, stage_gate_state transitions to "Ungated" and gate_resolution records option, approver_id, timestamp, and artifacts And unauthorized users receive a permission error and no state change occurs
Configurable Risk Thresholds and Gate Behavior
Given firm settings include gate_risk_threshold and block_on_unresolved and optional practice_area overrides When conflict scan results update for an intake Then the gate activates only when risk_score >= applicable_threshold OR (block_on_unresolved = true AND conflict_status = Unresolved) And changing the threshold or flags affects new evaluations immediately and existing intakes upon the next scan update event And practice_area-specific settings override firm defaults when intake.practice_area is set And all settings changes are audit-logged with old_value, new_value, actor_id, and timestamp
Timeout Auto-Cancels Stalled Gated Intakes
Given an intake with stage_gate_state = "Gated" and no resolution within firm.gate_timeout_hours When the timeout elapses Then intake.status transitions to "Cancelled_ConflictTimeout" and downstream actions remain disabled And notifications are sent to the intake owner and firm admin via in-app and email within 1 minute And any scheduled consultations associated with the intake are automatically cancelled with reason = "Conflict Gate Timeout" And reactivation requires either a new intake or an explicit authorized override per policy
User-Facing Explanations and Firm Policy Links Display
Given an intake with stage_gate_state = "Gated" When a staff user views the intake Then a banner explains the gate_reason in plain language and outlines next steps And a "View Firm Policy" link opens the firm-configured policy URL in a new tab And the banner content is screen-reader accessible and meets WCAG 2.1 AA contrast requirements And localized text displays according to the user’s language setting when translations exist
Jurisdiction-Aware Conflict Rules
"As a firm administrator, I want conflict evaluations to reflect our jurisdictions and policies so that risk decisions are consistent and defensible."
Description

Implements a configurable rule engine that evaluates potential conflicts based on jurisdiction, matter type, and firm policy, differentiating direct adversity, former client, prospective client, and third-party relationships. Supports effective-dated rule versions, per-office variations, and tunable risk thresholds that influence gating behavior. Includes a simulation/test mode to validate rule changes against historical data before deployment, plus an admin UI for safe updates without code changes.

Acceptance Criteria
Apply Effective-Dated Rules by Jurisdiction and Matter Type
Given an intake with start timestamp T, jurisdiction J, and matter type M And multiple rule versions exist for scope (J, M) with various effectiveDate values When the engine evaluates conflicts Then it selects and applies the rule version with the greatest effectiveDate that is <= T And it does not apply any rule version with effectiveDate > T And it does not apply rules for any scope other than (J, M)
Per-Office Variations Override Firm Defaults
Given a firm has a firm-level default rule Rf for scope (J, M) and office O has an override Ro And the intake is associated to office O When the engine evaluates conflicts Then Ro is applied instead of Rf And if no office override exists for O, Rf is applied And the evaluation output records the applied rule source as "office" or "firm"
Relationship Type Categorization and Scoring
Given candidate entities potentially related to the intake party via firm records When the engine classifies relationship types per policy Then each potential conflict is categorized as one of [direct adversity, former client, prospective client, third-party] And a numeric riskScore is computed using category-specific weights and is directly comparable to firm-defined thresholds And the output includes category, riskScore, and evidence references for each hit
Risk Thresholds Drive Stage Gates
Given firm-defined thresholds "low", "medium", and "high" with numeric cutoffs And the engine returns a hit with riskScore S When Instant Guard processes gating for the intake Then if S >= high cutoff, engagement steps are auto-halted and state is set to "Conflict Hold" And if medium cutoff <= S < high cutoff, caller disambiguation is prompted and supervisor approval is required to proceed And if S < medium cutoff, the intake proceeds without gating and the hit is logged only And all gating decisions are timestamped and recorded in the audit log
Simulation Mode Validates Rule Changes
Given an admin selects Simulation mode with a proposed rule set version V and a historical dataset H When the simulation is executed Then conflicts are evaluated using V against H without changing any production gating or records And a report is generated summarizing differences versus current rules, including counts by severity, list of newly blocked matters, and false-positive delta And the simulation results are stored and viewable in the admin UI
Admin UI Safe Rule Updates and Audit Trail
Given a user with the "Conflict Rules Admin" role opens the Rules UI When they create or edit a rule Then fields jurisdiction, matterType, relationshipTypes, threshold settings, effectiveDate, and scope (firm or office) are required and validated And overlapping effectiveDate ranges for the same scope are prevented And the user can preview impacted offices and threshold changes before saving And upon save, a new immutable rule version is created with audit details (user, timestamp, change summary) And activation is blocked if no firm-level default policy is defined And the admin can roll back to any prior version without code deployment
Fallback to Firm Default When No Matching Rules
Given an intake with jurisdiction J and matter type M where no matching office-specific rules exist When the engine evaluates conflicts Then the firm-level default conflict policy is applied And the applied policy source is recorded as "firm default" And gating behavior follows the default policy
Data Minimization and PII Safeguards
"As a privacy-conscious client, I want the system to avoid storing unnecessary personal data during conflict checks so that my information remains protected if I don’t proceed."
Description

Prevents persistence of sensitive intake data until conflict status is cleared, using ephemeral storage for disambiguation responses and field-level encryption for any temporarily held data. Masks sensitive values in logs and UI, enforces least-privilege access, and applies configurable retention policies with automatic redaction on abandoned or declined intakes. Provides consent messaging tailored to conflict screening and documents data handling decisions for compliance.

Acceptance Criteria
No Persistence Before Conflict Clearance
Given a new intake session begins and conflict status is Pending or High-Risk, When sensitive (PII/Sensitive) fields are entered, Then values are not written to durable storage and are held only in client memory or server ephemeral cache with a TTL ≤ 15 minutes. Given conflict status changes to Clear or an Explicit Override is approved, When the user saves the intake, Then only the minimum necessary fields for matter creation are persisted to durable storage and all other buffered sensitive values are discarded. Given conflict remains High-Risk or Pending beyond 24 hours or the session ends, When the session terminates, Then all buffered sensitive values are irreversibly discarded and do not appear in databases, logs, or analytics.
Ephemeral Disambiguation Data Handling
Given the system prompts for disambiguation (middle name, birth month, last‑4 phone), When the caller provides values, Then the values are stored only in ephemeral memory with a per-item TTL ≤ 10 minutes and are deleted on conflict decision or TTL expiry, whichever comes first. Given ephemeral disambiguation values exist, When the application process restarts or crashes, Then the values are not recoverable from disk, swap, or logs. Given a support or admin user views the live session, When disambiguation values are displayed, Then they are masked in UI and become unretrievable after deletion.
Field-Level Encryption for Temporarily Held Data
Given a sensitive field must be cached for screening longer than 60 seconds, When the value is stored server-side, Then it is encrypted at rest using AES-256-GCM with a unique per-record DEK wrapped by KMS and includes integrity protection. Given a service or user requests to read a temporarily held encrypted value, When decryption is attempted, Then the request is authorized by least-privilege role, access is logged with principal ID, purpose "screening", and timestamp, and decryption succeeds only via KMS. Given a decryption or integrity check fails, When the value cannot be read, Then the value is discarded, the user is re-prompted, and a security alert is generated.
Sensitive Data Masking in UI and Logs
Given sensitive fields are shown during intake, When rendered in the UI, Then values are masked by default (e.g., phone last‑4, email local-part partial, DOB month+year) and full reveal requires a one-time view with role-based permission and stated reason. Given server logs, traces, and error handlers, When validation or system errors occur, Then sensitive field values are never logged; redaction tokens (e.g., **** or [REDACTED]) appear instead in all outputs. Given a one-time view is used, When the reveal occurs, Then an audit event records viewer, reason, fields revealed, and a view token that expires within 5 minutes.
Least-Privilege Access Enforcement
Given roles (Intake Agent, Attorney, Admin, Support) exist, When accessing sensitive fields before conflict clearance, Then only the screening service may access raw values; human roles cannot view raw values until status is Clear or an Explicit Override with dual approval is recorded. Given API requests for sensitive fields are made, When scopes are evaluated, Then access is denied by default and allowed only to scopes screening:read-ephemeral and screening:decrypt-temp; all denials/approvals are logged and rate-limited. Given a privilege escalation is requested, When approval is sought, Then Attorney and Admin must both approve within 15 minutes with justification; otherwise the request is auto-denied.
Retention Policy and Auto-Redaction on Abandoned/Declined Intakes
Given an intake is Abandoned (inactivity > 72 hours) or marked Declined/High-Risk, When the status is set, Then the system auto-redacts all sensitive fields within 15 minutes, preserving only non-PII metadata (timestamps, status, conflict hash). Given backups, replicas, and search indexes exist, When redaction runs, Then redacted values are purged or cryptographically shredded across all stores within 24 hours and a verification job records success per intake. Given a legal hold is applied to an intake, When redaction would otherwise occur, Then redaction is paused; values remain encrypted and inaccessible without a hold token, and redaction resumes automatically upon hold release.
Consent Messaging and Compliance Logging
Given disambiguation is requested for conflict screening, When the prompt is shown, Then consent messaging explains purpose, ephemeral handling, retention, and non-engagement status, and the caller must affirm consent (checkbox + timestamp) before input is accepted. Given consent is captured, When records are stored, Then a non-PII consent record is saved with session ID, language version, and a hash of the consent text; the record is exportable for compliance. Given any data-handling decision occurs (e.g., extended ephemeral storage, decryption, override), When the action completes, Then an immutable, hash-chained audit entry is written with who/what/when/why and retained for 7 years, queryable by session or matter.
Conflict Decision Audit Trail and Overrides
"As a compliance officer, I want a comprehensive audit trail of conflict decisions and overrides so that we can demonstrate ethical compliance during reviews."
Description

Creates an immutable, time-stamped record of all scans, prompts, decisions, and overrides, including the user, reason codes, evidence snapshots, and resulting actions. Requires justification and appropriate authorization for overrides, supports multi-step approvals, and generates exportable reports for ethics audits. Ensures log integrity with tamper-evident hashing and provides retention controls aligned with firm policy.

Acceptance Criteria
End-to-End Logging of Scans, Prompts, Decisions, and Stage-Gate Actions
Given an intake session triggers a conflict scan When the scan executes Then an audit event is recorded with event_type="scan_executed", ISO 8601 timestamp with timezone, scan_parameters, result_summary (hits_count, risk_score), and actor="system" Given a disambiguation prompt is presented When the user submits responses Then an audit event "disambiguation_response" is recorded with prompt_id, fields_requested, fields_provided (masked where applicable), actor=user_id, and a correlation_id linking to the scan Given a conflict decision is saved (clear/monitor/conflict) When the decision is persisted Then an audit event is recorded with decision, reason_code, free_text_note (if provided), resulting_action (proceed/halt/escalate), and stage_gate_state Given an override is attempted or applied When the action occurs Then an audit event records override_status (requested/approved/denied/applied), approver_ids (if any), and evidence_references Rule: All events in the session share a session_id and/or matter_id, are strictly ordered via sequence_number, and become queryable within 2 seconds of write Rule: Events missing required fields are rejected with HTTP 400 and no partial writes occur
Immutability and Tamper-Evident Hash Chain
Given an audit record has been created When any user attempts to edit or delete it via UI or API before retention expiry Then the operation is blocked with HTTP 403 and a "tamper_attempt" audit event is recorded Given an audit record is written Then record_hash = SHA-256(canonical_record + previous_record_hash) is stored and exposed for verification And chain verification over any contiguous range returns "valid" Given the daily anchoring job runs When it completes Then the day’s root hash is anchored to an external immutable store and anchor_id is recorded in the system Given storage-layer manipulation occurs outside the application When integrity verification runs (scheduled every 5 minutes or on demand) Then it detects the mismatch and raises a critical alert within 1 minute, including affected record_ids
Override Justification and Authorization Enforcement
Given a high-risk conflict hit sets Stage Gate to "halted" When a user initiates an override request Then the UI requires selection of a reason_code from the managed list and a justification text of at least 20 characters, plus at least one evidence attachment or link; otherwise the Submit action remains disabled When the override request is submitted Then it is stamped with requester_id, timestamp, target decision, and becomes read-only to the requester Given a user without override permission attempts to submit When the request is sent Then the system responds HTTP 403, no override record is created, and a "permission_denied" audit event is logged
Risk-Based Multi-Step Approval Workflow
Given firm policy requires 2 approvals for high-risk overrides and 1 approval for medium-risk When an override request is created with risk_level=high Then the workflow routes sequentially to the configured approver roles and blocks matter progression until all required approvals are granted When an approver acts Then the system records decision (approve/deny), reason_note, timestamp, and actor, and notifies the next participant or requester within 60 seconds If any approver denies or the 24-hour SLA expires Then the request state becomes "denied" or "escalated" respectively, Stage Gate remains "halted", and resubmission requires a new request Rule: The same user cannot both request and approve, and cannot fulfill multiple required approvals on the same request
Exportable Ethics Audit Report Generation
Given a user with Audit Export permission selects a date range and filters (e.g., practice area, matter_id) When Generate Report is invoked Then an export is produced within 60 seconds for up to 50,000 events Rule: Exports are available in CSV and JSON; PDF summary includes counts by event_type, overrides, approvals, and failures Rule: Each row includes event_id, timestamp, actor, event_type, matter_id, session_id, reason_code, evidence_refs, resulting_action, record_hash, previous_record_hash Rule: The archive includes chain_verification.txt with verification result and daily anchor ids, is digitally signed, and the download action is audit-logged Rule: Redaction options (Mask PII, Include Evidence Snapshots) are honored; masked fields use consistent tokenization; unauthorized users receive HTTP 403
Retention Policy and Legal Hold Enforcement
Given firm policy defines retention_days for audit events and evidence snapshots When the nightly retention job runs Then items past retention and not under legal hold are purged or redacted per policy, leaving a tombstone with event_id, timestamp, record_hash, and purge_reason Then post-purge chain verification passes via tombstone linkage (no gaps) Given a legal hold is placed on a matter When retention jobs execute Then no related records are purged until the hold is removed; holds capture owner, reason, start_time, and end_time (if any) Rule: All retention actions (purge, redact, skip_due_to_hold) are audit-logged and reportable Rule: Retention policy changes require admin role, are versioned, and apply on the next retention cycle
Operator Console Alerts and Escalation
"As an intake specialist, I want clear on-screen guidance and fast escalation when a conflict arises so that I can handle the call efficiently and avoid delays."
Description

Delivers real-time, actionable alerts to intake staff with match details, confidence, and recommended next steps. Enables one-click escalation to an attorney review queue with SLA timers, canned scripts for caller messaging, and integrated task creation. Provides keyboard-accessible, color-blind-safe UI components and integrates with firm communication channels (email, SMS, Slack) for timely responses.

Acceptance Criteria
Real-Time Conflict Alert in Operator Console
Given an active intake session with live conflict scanning enabled When the conflict engine returns a potential match for the current party Then the operator console displays an alert within 2 seconds of the match event And the alert includes: masked party identifiers, matched entity type, confidence score (0–100%), risk level, match reasons, and recommended next steps And a "View match details" control expands to show all matched fields and data sources And the alert severity icon and label are present and unambiguous And the alert is announced to assistive tech (aria-live polite for Low/Medium, assertive for High)
One-Click Escalation to Attorney Review Queue
Given a visible conflict alert When the operator clicks "Escalate" Then a Review item is created with intake ID, match details, risk level, and correlation ID And an SLA target is set based on risk: High=15 minutes, Medium=60 minutes, Low=4 hours And a countdown timer is visible to the operator and in the attorney review queue And a task is created and assigned to the on-call attorney group with due time equal to the SLA target And the alert status changes to Escalated and the "Escalate" control is disabled to prevent duplicates And the operator sees a success confirmation within 1 second or a clear error message if creation fails, with no duplicate items created
Canned Caller Messaging Scripts
Given a conflict alert is open When the operator opens Caller Scripts Then the system shows at least three canned scripts tailored to the alert’s risk level and jurisdiction And dynamic fields (caller first name, matter type, firm name) are merged with no unresolved placeholders And clicking Copy places the selected script into the clipboard and shows a "Copied" confirmation And scripts update automatically if the risk level changes And operator edits to a script are local to the interaction (do not modify templates) and are recorded on the interaction log
Multi-Channel Notification Delivery
Given an escalated alert of Medium or High risk When notifications are dispatched Then email, SMS, and Slack messages are sent to configured recipients within 30 seconds And each notification records delivery status per channel And successful delivery rate is at least 95% within 5 minutes under normal operating conditions And failures are retried with exponential backoff up to 3 attempts And on permanent failure, a fallback email is sent to a backup distribution and the operator is alerted in-console And each notification contains the review link, summary, SLA deadline timestamp, and a unique correlation ID
Keyboard-Accessible and Color-Blind-Safe Alert UI
Given the operator navigates the console using only a keyboard When traversing the alert and escalation controls Then all interactive elements are reachable in a logical tab order and have visible focus indicators (>=3:1 contrast) And Enter/Space activates controls and Esc closes modals without requiring a mouse And color contrast meets WCAG 2.1 AA (text >=4.5:1; large text/icons >=3:1) And severity is communicated by icon/shape and text labels, not color alone And all controls have accessible names/roles/states for screen readers with zero critical AXE violations And severity cues remain distinguishable under simulated Protanopia, Deuteranopia, and Tritanopia
Alert Acknowledgment and Audit Trail
Given a visible conflict alert When the operator clicks "Acknowledge" Then the alert state changes to Acknowledged with timestamp and operator ID And the SLA timer continues until an attorney accepts the review item And all actions (viewed, expanded, acknowledged, escalated, notifications, failures) are logged with ISO 8601 timestamps, actor, and correlation ID And audit entries appear in the case activity feed within 1 second of the action And alert state changes synchronize across operator consoles within 2 seconds
Stage Gate Auto-Halt on High-Risk Conflict
Given a High-risk conflict match is detected during intake When the alert is raised Then engagement steps (retainer, e-sign, document requests) are disabled and a non-dismissible banner explains the halt and reason And the operator cannot proceed past the halted steps without attorney clearance When an attorney marks the review item as Cleared Then halted steps are re-enabled immediately When an attorney marks the review item as Blocked Then the intake is marked Conflict-Blocked and matter creation is prevented And attempts to override are blocked with a permission error and logged

SafeLink Invites

Send conflict‑safe, separate invitations to each spouse via unique SMS/email links that never expose the other’s contact or responses. Built‑in consent capture, re‑invite controls, and expiry tokens keep intake compliant and moving, reducing no‑shows while maintaining trust on both sides.

Requirements

Unique SafeLink Tokenization & Delivery
"As a solo attorney, I want to send each spouse a unique, expiring intake link via SMS or email so that each can complete intake privately without accessing the other’s information."
Description

Generate cryptographically secure, single-use intake URLs per party bound to matter ID and party role, with configurable expiry, automatic invalidation upon re-issue, and localization support for message templates. Deliver via SMS and/or email with sender identity controls, link preview suppression, and deliverability checks (bounce, spam, soft fail). Log all delivery events and link lifecycle states. Integrates with CaseSpark communications service and triggers intake workflow initiation upon first access.

Acceptance Criteria
Single-Use, Role-Bound SafeLink Token Generation
Given a matterId "M-001" and party role "Petitioner" When a SafeLink is generated Then a cryptographically secure, URL-safe token with at least 128 bits of entropy is created. And the token is uniquely bound to matterId "M-001" and role "Petitioner" so it cannot be used to access any other matterId or role. When the token is presented for a different matterId or role Then the request is denied with HTTP 403 and no party data is returned. When the token is accessed successfully the first time by a human browser Then the token state changes to "used" and subsequent requests with the same token return HTTP 410 Gone.
Configurable Expiry and Auto-Invalidation on Re-Issue
Given a tenant default expiry of 72 hours and no per-invite override When a SafeLink is created Then the token expiry is set to 72 hours from creation in UTC. Given a per-invite expiry override of 24 hours When a SafeLink is created Then the token expires 24 hours from creation in UTC. When a token has passed its expiry Then any access attempts return an "Expired" page and HTTP 410 without starting intake. When a new SafeLink is re-issued for the same matterId and role Then all previous tokens for that matterId and role are invalidated immediately and return HTTP 410. And a "TokenInvalidated" lifecycle event is recorded for each invalidated token with timestamp and actor.
Localized Message Templates and Personalization
Given recipient locale "es-MX" When the invite is generated Then the SMS/email uses the "es-MX" template variant for subject/body and formats dates/times per locale. When no recipient locale is provided Then the default locale "en-US" is used. When rendering the message Then placeholders {recipientName}, {firmName}, {matterIdShort}, {expiryDateTime} are resolved with correct values and no unresolved placeholders remain. When a locale-specific template is missing Then the system falls back to "en-US" and records a "TemplateFallback" event with locale code.
SMS and Email Delivery with Sender Identity Controls
Given the sender identity "intake@firm.com" with display name "CaseSpark Intake" is selected When an email invite is sent Then the From and Reply-To headers match the selected identity and the message is sent via CaseSpark communications service with a provider messageId recorded. Given the sender identity "FirmSMS" is selected When an SMS invite is sent Then the message is sent from the configured sender and a provider messageId is recorded. When a user without permission attempts to send from a restricted sender identity Then the action is blocked with HTTP 403 and no message is queued. When both SMS and email are selected for the same party Then both messages are sent referencing the same token and no duplicate tokens are created.
Link Preview Suppression and Non-Consumption by Prefetchers
Given a SafeLink URL When it is fetched by a known link preview user agent (facebookexternalhit, WhatsApp, Slackbot, Twitterbot, iMessagePreviewAgent) Then the server returns a non-unfurlable response (HTTP 204 or minimal text without OpenGraph tags) and the token remains in "unused" state. And the preview fetch is logged as "PreviewFetch" with userAgent and IP, but not counted as an access. When the human recipient taps the link in the client Then the intake landing page is rendered, the token is marked "used", and the preview suppression does not block the human access.
Deliverability Checks and Lifecycle Event Logging
When an email bounces with a 5xx code Then an "EmailBounceHard" event is recorded with SMTP code, reason, provider metadata, matterId, partyRole, and messageId. When an email results in a 4xx transient error Then an "EmailSoftFail" event is recorded and automatic retry occurs per policy until max attempts, after which "EmailBounceSoftFinal" is recorded. When an email spam complaint is received Then an "EmailSpamComplaint" event is recorded and further invites to that address are suppressed. When an SMS is undeliverable or filtered by carrier Then an "SmsUndeliverable" or "SmsFiltered" event is recorded with carrier code and reason. For successful deliveries Then a "Delivered" event is recorded for each channel with timestamp and provider messageId. For link lifecycle Then "TokenCreated", "Sent", "Delivered", "PreviewFetch", "Accessed", "Used", "Expired", "Invalidated", and "Reissued" events are recorded with ISO-8601 UTC timestamps and actor/system identifiers.
Intake Workflow Initiation on First Human Access
Given a valid unused token for matterId "M-001" and role "Respondent" When the recipient first accesses the SafeLink Then a new intake workflow instance for "M-001/Respondent" is created (or resumed if already exists) and set to status "In Progress". And the operation is idempotent: repeated valid accesses after the first do not create duplicate workflow instances. Then an "IntakeStarted" event is recorded with tokenId, workflowId, timestamp, and source IP/userAgent. When access is attempted with an expired or invalidated token Then the intake workflow is not started and an "AccessDenied" event is recorded.
Party Isolation & Response Segregation
"As an intake coordinator, I want each spouse’s contact info and answers kept strictly separate so that we maintain confidentiality and avoid trust issues."
Description

Enforce strict data isolation so each spouse’s invite, session, and responses are partitioned and never expose the other party’s identity, contact information, or answers. Bind each response set to its own party record with role-based access and view redaction. Allow conflict screening to leverage both parties’ identifiers without cross-surface leakage. Ensure notifications and reminders reference only the recipient’s own data. Provide configuration to disable any cross-party messaging and to redact names in all client-facing communications.

Acceptance Criteria
Isolated SafeLink Tokens Per Party
Given a matter with two parties A and B, When invitations are sent via SMS and email, Then A and B each receive a unique, single-party tokenized link bound to their party_id and channel. Given party A’s link, When the link is opened, Then the intake UI, payloads, and network responses contain no fields identifying party B (name, email, phone, answers, files). Given party A’s link, When the token is manipulated to any other value or reused after expiry, Then the system returns 410 (expired) or 404 (invalid) without revealing any party or matter identifiers and writes a security audit log entry.
Session and Storage Partitioning by Party
Given party A authenticates and completes intake steps, When answers are saved, Then they are persisted under a partition key composed of tenant_id+matter_id+party_id and are not retrievable via party B’s token. Given simultaneous sessions by A and B from different devices, When autosave occurs, Then no localStorage/cookie/session keys are shared; only keys namespaced to each party_id exist. Given API access with a valid token for party A, When requesting any endpoint for responses, files, or progress, Then the API returns only A’s records and 403 for any attempt to access B’s resources.
Role-Based Access with Redacted Cross-Party Views
Given staff roles Intake, Attorney, Admin, and External-Viewer, When viewing a matter, Then server-side permissions restrict access so only authorized roles can view both parties’ responses; External-Viewer can view only the assigned party. Given configuration redact_cross_party_views=true, When any staff views party A’s response detail, Then fields referencing party B (name, contact, identifiers) are masked with placeholders and excluded from exports and print views. Given a direct URL to party B’s response set, When accessed by a user lacking B_VIEW permission, Then the system responds 403 and records the attempt in audit logs.
Conflict Screening Without Client-Side Leakage
Given identifiers for both parties are captured, When the conflict screening job runs, Then it queries using both parties’ identifiers and writes results to an internal report not accessible via client-facing endpoints. Given a positive conflict hit, When party A is viewing intake, Then any messaging is generic (e.g., “We need to contact you”) and contains no data derived from party B’s identifiers or hit details. Given API calls from party A’s session, When inspecting all JSON responses during conflict processing, Then no payload contains party B’s PII, identifiers, or conflict results; any references are absent or null.
Recipient-Only Notifications and Reminders
Given reminders are scheduled for parties A and B, When a notification is sent to A via SMS/email, Then the subject, body, merge fields, and links include only A’s data and contain no tokens or parameters that can access B’s data. Given document attachments or summaries are sent to A, When the message is delivered, Then the attachment contains only A’s content and no cross-party references; checksum differs from any attachment sent to B. Given sending logs, When reviewing the record for a notification to A, Then metadata shows only A’s contact, party_id, and link; B’s contact details are absent.
Configurable Cross-Party Messaging Disablement
Given the setting disable_cross_party_messaging=true at tenant or matter level, When a user attempts to send a message from within A’s context to B, Then the UI blocks the action with a clear reason and the API returns 400 with code CROSS_PARTY_MESSAGING_DISABLED. Given the same setting, When any automated workflow attempts to queue a message to the opposite party, Then the message is not queued, a warning is logged, and no notification is sent. Given the setting is toggled to false, When the same actions are retried, Then the system allows the messages subject to role permissions.
Redacted Names in All Client-Facing Communications
Given redact_names_in_client_comms=true, When rendering any client-facing screen, email, SMS, or PDF for party A, Then the other party is referred to generically (e.g., “the other party”) and no proper names or initials of B appear. Given templates with merge fields that could reference the other party, When generating content for party A, Then those fields resolve to empty or generic text, never to B’s name/contact. Given delivery of multi-language communications, When inspecting all locales for A, Then redaction is applied consistently across languages and channels; QA tests confirm zero occurrences of B’s name.
Consent Capture & Audit Trail
"As a firm owner, I want explicit consent and an auditable record for each invitation so that we remain compliant and can prove consent if challenged."
Description

Capture explicit consent for SMS/email communications, privacy policy, and e-sign related notices prior to or at first SafeLink access. Record timestamp, IP, user agent, invite ID, consent text version, and jurisdictional basis. Store an immutable, exportable audit record (PDF/JSON) linked to the matter and party. Support consent revocation and re-consent flows with history. Surface consent status in CaseSpark’s global audit log and expose via API/webhook for downstream compliance and e-discovery needs.

Acceptance Criteria
Gate Access Until Required Consents Granted
Given a recipient opens a SafeLink for the first time When the consent screen is presented Then the recipient cannot view any intake data until they explicitly accept the privacy policy and e-sign notices And channel consents for SMS and email are captured separately Given the recipient accepts required consents and submits When validation succeeds Then access to the SafeLink intake is granted for that session And channel communications are enabled only for the channels consented to Given the recipient previously consented for the same invite and consent text version and jurisdictional basis When they reopen the SafeLink Then the consent screen is not shown again Given the consent text version or jurisdictional basis has changed since last consent When the recipient opens the SafeLink Then the updated consent screen is shown and must be accepted before access resumes
Consent Metadata Capture and Storage
Given a consent decision (grant or decline per channel) is submitted When the system persists the event Then it stores timestamp in UTC ISO 8601, IP address (IPv4/IPv6), user agent (raw), invite ID, matter ID, party ID, consent text version ID, jurisdictional basis code, per-channel decisions, and the contact identifier used (email or phone hashed) And the record is write-once and cannot be edited in place Given rapid repeat submissions (e.g., double-click) within 5 seconds for the same invite and payload When idempotency is applied Then only one consent event is stored Given data at rest When inspected Then consent records are encrypted at rest according to platform standards
Immutable, Exportable Audit Record (PDF/JSON)
Given a matter-party has at least one consent event When an authorized user or API client requests an audit export Then the system generates a JSON export and a PDF export within 10 seconds And each export includes all required fields (timestamp_utc, ip, user_agent, invite_id, matter_id, party_id, consent_text_version, jurisdiction_basis, channel_states, event_type, event_id) And each export is party-scoped and contains no PII of the other spouse/party And each export includes a SHA-256 checksum and record count Given an export is generated When a consumer verifies integrity Then the checksum validates the content And the export is accessible via a signed URL that expires within 24 hours
Consent Revocation and Immediate Enforcement
Given a recipient revokes SMS consent via STOP or the preferences link When the revocation is received Then a revocation event is stored with full metadata and prior consents remain in history And all outbound SMS to that party for the matter cease within 2 minutes across all delivery paths Given a recipient revokes email consent via unsubscribe or preferences When the revocation is received Then a revocation event is stored and email sending to that address for the matter is blocked within 2 minutes Given a revoked channel When staff attempt to send via that channel Then the UI/API prevents the send and surfaces the revocation reason and timestamp
Re-Consent Flow with Full History
Given a party has revoked a channel or the consent text version has changed When they re-access SafeLink or receive a re-invite Then the system presents the current consent text version and jurisdictional basis for re-consent And upon acceptance, a new consent event is stored without overwriting prior events Given re-consent was granted for a previously revoked channel When staff send communications via that channel Then sending is permitted Given re-consent is declined When staff attempt to send via that channel Then sending remains blocked and the latest decision is displayed with timestamp
Global Audit Log and In-App Surfacing
Given a user with Audit permissions opens the global audit log When they filter by date range, matter ID, party ID, invite ID, event type, channel, or jurisdictional basis Then matching consent events are returned with pagination And each row displays current consent status per channel, latest consent text version, and links to the matter and party Given a matter or party detail page is opened When it loads Then current consent statuses (Granted/Revoked/Pending) per channel and the latest consent timestamp are visible And no other party’s contact details or responses are exposed
API and Webhook Delivery for Compliance/E-Discovery
Given webhooks are configured for the tenant When a consent is granted, revoked, or re-consented Then a webhook is delivered within 15 seconds with payload fields: event_type, occurred_at_utc, matter_id, party_id, invite_id, event_id, channel_states, consent_text_version, jurisdiction_basis, ip, user_agent, actor_contact_hash, audit_export_json_url, audit_export_pdf_url, signature_hmac And on non-2xx response, retries occur with exponential backoff up to 5 attempts before dead-lettering Given an API client with consents:read scope requests GET /v1/consents with filters When the request is valid Then the API returns paginated results including required metadata and excludes any PII of the other spouse/party And responses include an ETag for cache validation
Re-Invite, Reminder & Expiry Management
"As a paralegal, I want to re-send or extend an intake link and schedule reminders so that clients complete intake without manual chasing."
Description

Provide staff controls to resend invitations, schedule automated reminders, and extend or revoke link expiry with a full event history. Automatically invalidate old links upon re-issue. Apply configurable throttling to prevent spam and respect opt-outs. Handle bounces and undeliverable messages with actionable alerts. Track open, verify, start, and complete events to drive smart reminder timing and in-app tasks for stalled invites. Allow per-matter and global policy settings for cadence and expiry windows.

Acceptance Criteria
One-Click Re-Invite Invalidates Prior Links
Given an active invite link exists for a recipient on a matter When staff selects Re-Invite and chooses SMS and/or email channels Then the system issues a new unique tokenized link, marks all prior tokens for that recipient as invalidated with cause=reissue, and records a timestamped audit event And the newly issued link is sent only to the selected channels using the current templates without including any information about the other spouse And any attempt to access a prior link returns a standardized "Link expired or replaced" screen without exposing matter details and logs an invalid_attempt event with IP, user agent, and timestamp And the other spouse’s invitation status and tokens remain unchanged
Automated Reminder Cadence by Policy with Pause/Resume
Given global reminder cadence and send-window policies exist and a matter may define overrides And an invite is sent but not yet completed When the system evaluates reminder eligibility Then reminders are scheduled according to the resolved policy (global or per-matter override) and recipient-local send windows And if the invite is opened or completed, all pending reminders for that invite are automatically canceled and audit logged And when staff pauses reminders on the matter, no reminders are sent while paused; upon resume, only future reminders (not past-due) are scheduled per policy and all actions are audit logged
Expiry Token Extension and Revocation with Audit Trail
Given an invite link has an expiry derived from policy When staff extends the expiry by a specified duration within allowed bounds Then the new expiry replaces the old, and an audit event captures actor, previous expiry, new expiry, reason, and timestamp When staff revokes the invite Then the token status becomes revoked immediately, the link becomes unusable, an audit event is recorded, and the recipient sees a standardized "Link revoked" screen without matter details And all expiry/revocation changes are visible in the matter’s event history timeline
Throttling and Opt-Out Compliance for Invites and Reminders
Given throttling policies define max sends per recipient per channel per time window and per-matter totals When staff or automation attempts to send an invite or reminder exceeding the applicable throttle limit Then the send is blocked, a clear reason is shown to staff, and a throttle_block event is logged with counts and window When a recipient has opted out of a channel (e.g., SMS STOP or email unsubscribe) Then no messages are sent via that channel until an explicit re-opt-in is recorded; staff are prompted to choose an alternate channel; all decisions are audit logged And throttling and opt-out checks occur before each send (manual or automated)
Bounce and Undeliverable Handling with Actionable Alerts
Given delivery webhooks report hard bounces, repeated soft bounces per policy, or carrier blocks When such a condition is received for an invite or reminder Then the channel is marked undeliverable with the provider code and description, pending reminders on that channel are canceled, and a high-priority in-app alert and task are created for the assigned intake role within 1 minute And the task includes the last known contact details, failure reason, and a one-click action to retry after contact correction or to switch channel; all outcomes are audit logged And if a new valid contact is saved and verified, the system offers to resume the reminder schedule from the next eligible slot per policy
Event Tracking Drives Smart Reminders and Stalled Tasks
Given the system tracks invite_opened, identity_verified, intake_started, and intake_completed events with timestamps and channel When inactivity thresholds defined by policy elapse after invite_opened without intake_started Then a smart reminder is scheduled for the next eligible send window and audit logged When intake_started occurs but intake_completed does not within the configured completion window Then a nudge reminder is sent; on further lapse beyond the escalation window, an in-app task is created for staff follow-up And when intake_completed occurs, all pending reminders and tasks for that invite are canceled, and the full event timeline is visible in the matter
Per-Matter vs Global Policy Resolution and Schedule Preview
Given global defaults for cadence and expiry and allowed bounds for overrides When staff sets per-matter reminder cadence and expiry values Then the system validates entries against bounds, resolves the effective policy (per-matter over global), and shows a schedule preview of planned sends and expiry in the matter’s timezone before saving And after saving, only future events are updated; past or already-sent events remain unchanged; all changes are audit logged with before/after values And if global policies are later updated, matters without overrides adopt the new defaults; matters with overrides remain unaffected
Jurisdiction-Aware Intake Routing
"As a client, I want my intake to automatically adapt to my state’s requirements so that I only see relevant questions and the firm can generate correct filings."
Description

On SafeLink launch, route each party into the correct, role-specific intake flow using detected or declared jurisdiction and practice area. Enforce jurisdiction-required fields and dynamic branching while ensuring that each spouse only sees their own prompts. Localize content and compliance notices per jurisdiction. Pass sanitized, party-scoped outputs into conflict screening and document assembly pipelines without cross-party data exposure. Provide admin controls to customize routing rules and content variants.

Acceptance Criteria
Auto-Detect or Declare Jurisdiction Routes to Role-Specific Intake
- Given a SafeLink with an assigned party role is opened, When geo-IP or device location resolves to a supported jurisdiction and invite metadata includes practice area, Then the user is auto-routed to that jurisdiction’s role-specific intake without exposure to the other role’s prompts. - Given jurisdiction detection is ambiguous or unsupported, When the user must select from an allowed jurisdiction list, Then selection is required before any intake questions and is persisted to session and audit log. - Given a jurisdiction has been selected, When the user attempts to change jurisdiction mid-intake, Then the app requires explicit confirmation, clears jurisdiction-scoped answers, reapplies branching, and records the change event. - Given a SafeLink token encodes role=respondent, When opened on any device, Then the role cannot be changed by the user and all prompts remain respondent-specific.
Jurisdiction-Required Fields and Dynamic Branching Enforced
- Given jurisdiction X defines required fields set RX for family-law intake, When progressing past a page, Then the user cannot continue until all fields in RX on that page are valid; localized error messages identify each missing/invalid field. - Given an answer triggers jurisdiction-specific branching (e.g., minor children = Yes), When selected, Then the jurisdiction X child-related subflow is inserted with its own required fields and cannot be bypassed. - Given a previously answered upstream question is changed such that dependent fields are no longer applicable, When changed, Then dependent answers are invalidated, hidden, and excluded from outputs and submission. - Given unresolved required fields remain, When attempting final submission, Then submission is blocked and the first missing field is focused with a summary of unmet jurisdictional requirements.
Localized Content and Compliance Notices Per Jurisdiction
- Given jurisdiction X requires disclosure Y and supports languages {L1, L2}, When intake starts, Then prompts, help text, and compliance notices render using the jurisdiction X content variant in the selected supported language; no global fallback text is shown. - Given consent text is mandated for jurisdiction X, When the user accepts, Then the system stores timestamp, jurisdiction code, content version hash, IP, and user agent in an audit record tied to the session. - Given the user switches language within the jurisdiction’s supported set, When toggled, Then content remains jurisdiction-specific and consent is re-captured only if the consent text version differs between languages. - Given an unsupported language is requested, When loading, Then the system defaults to the jurisdiction’s primary language and disables language toggling.
Strict Party-Scoped Isolation Across SafeLink Sessions
- Given two SafeLinks issued to Party A and Party B, When Party A link is used, Then no UI, API, or URL reveals Party B’s contact info, answers, or existence; attempts to access Party B resources return 403 with a non-enumerating error. - Given manual URL manipulation or navigation attempts toward the other party’s routes, When attempted, Then the system redirects to the current party’s intake home and logs a security event with token ID and IP. - Given exports or dev tools inspection, When intake data is retrieved for Party A, Then only Party A fields are present; other-party fields are absent (not null placeholders) and identifiers are scoped to Party A only. - Given a SafeLink is forwarded, When opened on a new device, Then access requires OTP verification to the invited contact channel before any answers are displayed; role remains bound to the token.
Sanitized Party-Scoped Outputs to Conflict Screening and Assembly
- Given Party A completes intake, When the conflict screening pipeline executes, Then only Party A’s scoped fields are sent; Party B appears, if needed, as a non-identifying hash or minimal role/jurisdiction marker with no contact details. - Given document assembly for jurisdiction X and role Y, When generating drafts, Then only templates and clauses applicable to X and Y are applied; any cross-party statements are limited to sanitized references per policy. - Given downstream validation detects missing jurisdiction-required fields, When processing, Then the job is rejected with an actionable error listing missing field keys and jurisdiction code; no partial artifacts are persisted. - Given a successful pipeline run, When outputs are stored, Then an immutable audit record includes jurisdiction, role, routing rule ID, content version, and a checksum of the sanitized payload.
Admin Customization of Routing Rules and Content Variants
- Given an authorized admin, When creating or editing a routing rule, Then they can target by jurisdiction, practice area, invite source, and party role; each rule has priority, status (draft/published), and effective window. - Given localized content variants, When an admin edits prompts or compliance notices, Then changes are versioned; preview mode allows launching a sandbox SafeLink to validate routing/branching and localization before publish. - Given overlapping rules are detected, When attempting to publish, Then validation blocks publish and surfaces the conflicting rules with required resolution via priority or scope adjustment. - Given a rollback is initiated, When reverting to a prior version, Then new sessions use the reverted rules/content immediately; in-flight sessions continue on their pinned version unless the user opts into the update after re-consent.
Access Security & Identity Verification
"As a security-conscious attorney, I want OTP-protected, non-transferable intake links so that only the intended spouse can access and complete their forms."
Description

Protect SafeLinks with optional OTP verification (SMS/email), device/browser binding for resume, rate limiting, and anti-enumeration measures. Support one-time consumption semantics with secure resume tokens tied to the same device. Enforce session timeouts and lockouts after failed verifications. Encrypt data in transit and at rest, and log security events for monitoring. Allow firm-level configuration of verification strength by matter type and jurisdictional risk profile.

Acceptance Criteria
Firm-Level Verification Policy by Matter Type and Jurisdiction
Given a firm admin defines verification rules by matter type and jurisdictional risk profile, When a SafeLink is generated for a matching matter, Then the most restrictive applicable rule is selected and stored with the invite. Given two or more rules match a matter, When policy is evaluated, Then the rule precedence None < Email OTP < SMS OTP < SMS or Email OTP < SMS+Email OTP is enforced. Given a matter matches no specific rule, When a SafeLink is generated, Then the firm’s default verification rule is applied. Given a SafeLink has a stored rule, When the recipient opens the SafeLink, Then the stored rule’s challenge type(s) are enforced. Given a policy is changed after a SafeLink is issued, When the existing SafeLink is used, Then the originally stored rule continues to apply until a new invite is issued.
OTP Verification Enforcement (SMS/Email) Per Policy
Given policy requires SMS OTP, When the recipient opens the SafeLink, Then a 6-digit numeric OTP is sent only to the phone on file and the UI masks the number (e.g., ***-***-1234). Given policy requires Email OTP, When the recipient opens the SafeLink, Then a 6-digit numeric OTP is sent only to the email on file and the UI masks the address (e.g., j***@d***.com). Given an OTP is issued, When the recipient enters the correct code within 10 minutes, Then access is granted and the code is invalidated. Given an OTP is issued, When the recipient enters any incorrect or expired code, Then access is denied with a generic error and the code remains single-use. Given policy disables OTP, When the recipient opens the SafeLink, Then no OTP challenge is presented and access proceeds.
One-Time SafeLink Consumption with Device/Browser-Bound Resume
Given a fresh SafeLink, When the recipient completes the first successful verification, Then the SafeLink URL is marked consumed and cannot be used again from any device or browser. Given a successful verification, When a resume token is issued, Then it is bound to the same device/browser and allows resuming intake on that device for up to 72 hours without reusing the original SafeLink. Given a resume token exists, When a resume is attempted from a different device/browser, Then access is denied and no intake data is displayed. Given a re-invite is issued or the invite is revoked, When any prior consumed URL or resume token is used, Then access is denied. Given 72 hours elapse without resume activity, When the recipient attempts to resume, Then the system requires a new invitation to proceed.
Rate Limiting and Lockouts for OTP Sends and Attempts
Given an invite, When OTP sends exceed 5 in 15 minutes for that invite, Then further sends are blocked for 15 minutes and the API returns HTTP 429 with a Retry-After header. Given a recipient, When OTP sends across all invites exceed 10 in 24 hours to the same phone/email, Then further sends are blocked for the remainder of the 24-hour window. Given an invite, When 5 incorrect OTP submissions occur within 15 minutes, Then the invite is locked for 15 minutes and further submissions return a generic rate limit message. Given a locked invite, When the 15-minute lockout elapses, Then the recipient may request and verify a new OTP. Given an IP address, When OTP verification attempts across invites exceed 100 within 5 minutes, Then subsequent attempts from that IP receive HTTP 429 for the remainder of the window. Given a successful OTP verification, When counters are evaluated, Then per-invite incorrect-attempt counters are reset.
Anti-Enumeration and Privacy-Preserving Responses
Given any non-existent, expired, consumed, or revoked SafeLink, When it is accessed, Then the system returns the same generic UI message and HTTP 200 without revealing which condition applies. Given an OTP challenge, When contact details are displayed, Then phone numbers and emails are masked and no alternative channels not on file are shown. Given invalid or unauthorized access attempts, When the API responds, Then error bodies and status codes are indistinguishable between not-found and unauthorized cases. Given repeated invalid SafeLink requests, When responses are returned, Then server adds jitter so response time is randomized within a 300–600 ms window to reduce timing inference. Given a SafeLink invite for one spouse, When the other spouse’s existence or contact info could be inferred, Then no UI or API response contains any reference to the other party.
Session Timeout and Re-Verification on Inactivity
Given an active verified session, When 14 minutes of inactivity elapse, Then the user is warned with a 60-second countdown. Given the countdown elapses without activity, When 15 minutes of inactivity are reached, Then the session is terminated and access to intake forms is blocked. Given a session reaches an absolute lifetime of 60 minutes from verification, When the limit is reached, Then the session is terminated regardless of activity. Given a session is terminated due to timeout, When the recipient attempts to continue, Then access requires a valid device-bound resume token within its validity window; otherwise a new invite is required.
Encryption in Transit/At Rest and Security Event Logging
Given any SafeLink, OTP, or resume endpoint, When accessed over HTTP, Then the request is rejected and only HTTPS with TLS 1.2+ and HSTS is permitted. Given data at rest (PII, OTP secrets, resume tokens), When stored, Then it is encrypted using industry-standard strong encryption with keys managed by a KMS and tokens are signed to prevent tampering. Given an OTP is sent, verified (success/failure), a lockout or rate limit occurs, a link is consumed, a resume is attempted, or a policy is changed, When the event occurs, Then a security log entry is recorded with timestamp, firmId, inviteId (pseudonymous), eventType, outcome, source IP, and user agent. Given a firm admin with permissions, When they query security logs, Then entries for the last 12 months are retrievable and exportable in CSV and JSON formats. Given log integrity requirements, When logs are stored, Then entries are immutable (append-only) and any write failure is surfaced to monitoring without blocking the user action.
Invite Status Dashboard & Reporting
"As an office manager, I want a dashboard showing invite progress and conversion so that I can proactively intervene and optimize our intake process."
Description

Provide a real-time dashboard showing SafeLink invite lifecycle states (sent, delivered, opened, verified, started, completed, expired, bounced, opted-out) with filters by matter, attorney, channel, and date. Surface conversion and time-to-complete metrics, identify bottlenecks, and enable CSV/JSON export. Integrate with CaseSpark tasks to auto-create follow-ups on stalled or bounced invites. Offer webhook events for status changes to support external analytics and CRM sync.

Acceptance Criteria
Real-Time Invite Lifecycle Dashboard
- Given I am an authenticated firm user with access to the matter list When I open the Invite Status Dashboard Then I see total counts and percentages for each lifecycle state: sent, delivered, opened, verified, started, completed, expired, bounced, opted-out for the default date range (last 7 days) - Given an invite’s status changes When the change is recorded by CaseSpark Then the dashboard metrics and lists update within 5 seconds without a manual page refresh - Given lifecycle state definitions When I view the dashboard Then no invite is shown in more than one terminal state simultaneously and state transitions follow the allowed path: sent -> delivered -> opened -> verified -> started -> completed OR sent -> bounced OR sent -> expired OR opened -> opted-out - Given SafeLink privacy rules When I view any invite row Then the invitee’s contact is masked and no responses from either spouse are displayed
Filtered Views by Matter, Attorney, Channel, and Date
- Given there are invites across multiple matters, attorneys, channels, and dates When I apply filters for matter ID(s), attorney(s), channel(s) (SMS, email), and a date range (default: sent_at; option to switch to last_event_at) Then all counts, tables, funnels, and metrics reflect only invitations matching the intersection of selected filters - Given I have applied filters When I refresh the page within the same session Then my filter selections persist - Given large datasets When I filter Then the filtered results return within 2 seconds for result sets under 10,000 invites
Conversion and Time-to-Complete Metrics
- Given a filtered set of invites When I view metrics Then conversion rate is calculated as completed / sent and displayed to one decimal place - Given completed invites When I view time metrics Then median and 90th percentile time-to-complete (sent_at -> completed_at) are displayed in the firm time zone with units in minutes - Given channel and attorney breakdown toggles When I enable a breakdown Then conversion and time-to-complete are displayed per selected dimension and totals remain accurate
Bottleneck Identification and Funnel
- Given the lifecycle stages delivered, opened, verified, started, completed When I view the funnel Then step conversion percentages and average dwell time per step are displayed for the current filter - Given invites with no activity for 48 hours and not in a terminal state When I view the "Stalled invites" list Then I see the top 50 stalled invites with last_state, last_event_at (UTC), and days stalled, and I can sort by stall duration - Given a stall threshold setting When an admin updates the threshold between 12 and 168 hours Then the stalled list and task automation rules use the updated threshold within 1 minute
CSV/JSON Export
- Given a filtered dataset When I request an export as CSV or JSON Then the export contains only records matching the current filters and includes these fields: invite_id, matter_id, attorney_id, party_role, channel, current_state, sent_at, delivered_at, opened_at, verified_at, started_at, completed_at, expired_at, bounced_at, opted_out_at, last_event_at, last_error - Given the export is generated When I download the file Then timestamps are in ISO 8601 UTC, commas are properly escaped, and UTF-8 encoding is used - Given SafeLink privacy rules When I export Then no invitee message content or the other spouse’s contact details are included; email addresses are masked and phone numbers show only last 4 digits - Given a request for exports up to 100,000 rows When I initiate export Then the file is delivered synchronously within 10 seconds; for larger requests, an asynchronous export is queued and a secure download link is emailed within 15 minutes
Auto-Creation of Follow-Up Tasks for Stalled or Bounced Invites
- Given an invite becomes bounced or meets the stall threshold and is not completed When the condition is detected Then a CaseSpark task is created on the related matter with type "Follow up on SafeLink invite", assigned to the matter owner (fallback: intake coordinator), due next business day, and linked to the invite detail - Given an existing open follow-up task for the same invite and reason When the condition reoccurs Then no duplicate task is created - Given a follow-up task exists for an invite When the invite reaches completed or opted-out Then the task is automatically closed within 1 minute with a resolution note
Webhook Events for Invite Status Changes
- Given a tenant has configured a webhook endpoint and secret When an invite changes state or fails delivery Then a POST event is sent within 5 seconds with payload: event_id, tenant_id, matter_id, invite_id, previous_state, new_state, occurred_at (UTC), channel, party_role, and a SHA-256 HMAC signature header - Given transient delivery failures When the webhook delivery returns a network error or 5xx Then the system retries up to 5 times with exponential backoff (1s, 5s, 30s, 2m, 10m) and includes the same idempotency key header - Given idempotent processing When a receiver gets duplicate events Then the event_id and idempotency key enable safe de-duplication - Given SafeLink privacy rules When webhooks are delivered Then no invitee PII (full email, full phone, or responses) is included in the payload

MirrorSync

Generate perfectly mirrored, neutral‑tone questionnaires for both parties with jurisdiction‑aware branching. Shared fields (children, addresses, dates) sync into a common fact set while party‑specific details remain partitioned—cutting duplicate typing and keeping language non‑adversarial.

Requirements

Mirrored Questionnaire Generator
"As a family-law attorney, I want to generate mirrored, neutral questionnaires for both parties so that intake remains unbiased and efficient across jurisdictions."
Description

Automatically generates two jurisdiction-aware, neutral-tone questionnaires from a single intake schema, ensuring both parties receive functionally equivalent prompts with mirrored phrasing. Supports dynamic branching by case type and court rules, repeatable sections (e.g., children, assets), prefill from known client data, and safe defaults. Integrates with CaseSpark’s intake workflow builder and document assembly to ensure collected data flows directly into e-sign-ready filings. Reduces duplicate typing and maintains parity across parties while preserving a professional, non-adversarial tone.

Acceptance Criteria
Mirrored Neutral-Tone Generation
- Given an intake schema S with N prompts, When the generator runs, Then two questionnaires Q_client and Q_other are produced and have identical prompt IDs, count N, and ordering. - Given any prompt text in Q_client, When compared to the corresponding prompt in Q_other, Then the texts are mirrored by party perspective (pronoun/role swap) and contain no adversarial terms from a prohibited lexicon ["at fault","blame","accuse"]. - Given the generated questionnaires, When evaluated for readability, Then Flesch-Kincaid grade level <= 10 for all prompts. - Given schema updates, When S is modified and regenerated, Then both Q_client and Q_other reflect the change identically.
Jurisdiction-Aware Branching
- Given caseType = Dissolution and jurisdiction = JUR-A, When generating questionnaires, Then a ParentingPlan section is included and all fields marked required per rule R-PP-A. - Given caseType = Dissolution and jurisdiction = JUR-B, When generating questionnaires, Then no ParentingPlan section is present and no required fields reference it. - Given a ruleset version v, When generation runs, Then the applied branching decisions reference ruleset version v and are logged per prompt with rule IDs. - Given an invalid combination of caseType/jurisdiction, When generating, Then the system blocks generation and returns a validation error with code BRANCH-400 and a human-readable message.
Shared Field Sync and Party Partitioning
- Given a shared field (child.fullName) entered in Q_client, When saved, Then the common fact set is updated and Q_other displays the same value within 1 second. - Given a party-specific field (client.employer), When entered in Q_client, Then Q_other does not display or receive the value. - Given conflicting edits to a shared field from both parties within 5 minutes, When both are saved, Then the system applies last-writer-wins by timestamp and records both versions in an audit log with user, timestamp, and prior value. - Given a shared field cleared by one party, When synced, Then the other questionnaire displays a confirmation state requiring explicit acknowledgment before overwriting a previously confirmed value.
Repeatable Sections: Children and Assets
- Given repeatable section Children, When one child is added in Q_client with required fields complete, Then the child instance appears in Q_other with the same stable instance ID and field values within 1 second. - Given maxChildren = 10 in schema, When the 11th child is attempted, Then the system prevents addition and displays validation error REPEAT-422. - Given reordering of repeatable instances by drag-and-drop in Q_client, When saved, Then Q_other reflects the same order. - Given deletion of a repeatable instance in either questionnaire, When confirmed, Then the instance is removed from both questionnaires and the common fact set.
Prefill and Safe Defaults
- Given existing client profile data D in CaseSpark, When generating Q_client, Then fields with mappings in schema are prefilled from D and displayed with a 'Prefilled' indicator. - Given fields prefilled from one party's data that are not shared, When generating the other party's questionnaire, Then those values are not prefilled or exposed. - Given a required field without available data, When generating, Then a safe default placeholder (e.g., 'Select...') is applied rather than a guess, and the field remains required. - Given admin-configured prefill rules are changed, When regenerating questionnaires, Then the changes are applied and logged with config version and timestamp.
Workflow and Document Assembly Integration
- Given both questionnaires reach 100% completion and are submitted, When the workflow builder triggers document assembly, Then mapped fields populate the e-sign-ready filing templates with 100% coverage for required template fields; any unmapped optional fields are listed in a remediation report. - Given a template mapping error, When assembly runs, Then the system fails gracefully, logs the missing mappings, and surfaces a remediation list with field keys and template names. - Given successful assembly, When documents are produced, Then e-sign tags are placed at all signature fields and the package is ready for electronic execution without manual placement.
Duplicate Typing Reduction
- Given a schema with K shared fields and M party-specific fields, When Q_other is generated after Q_client has completed shared fields, Then at least 80% of K fields are auto-populated in Q_other and require only confirm-or-edit, not typing. - Given a baseline of total keystrokes measured during Q_client completion, When Q_other is completed with shared fields prefilled, Then total keystrokes for shared fields are reduced by at least 60%. - Given analytics are enabled, When both questionnaires are submitted, Then the system records duplicate typing savings metrics per case (shared fields count, auto-populated count, estimated time saved) to the analytics dashboard.
Shared Fact Sync Engine
"As an attorney, I want common facts like children’s names and addresses to sync automatically between both parties’ questionnaires so that I avoid duplicate entry and inconsistent filings."
Description

Creates and maintains a canonical common fact set for shared entities (children, addresses, dates, case metadata) and bi-directionally syncs those fields across both questionnaires in real time. Handles field-level provenance, deduplication, and change detection, with configurable rules for when updates auto-merge versus require review. Integrates with CaseSpark’s matter record, conflict screening, and document assembly so that updates to shared facts immediately propagate to filings, tasks, and checks without manual re-entry.

Acceptance Criteria
Real-Time Bi-Directional Sync Across Party Questionnaires
Given Party A and Party B questionnaires for the same matter are open and connected When Party A edits and saves a shared field (e.g., Child.DateOfBirth) Then the canonical fact set is updated with the new value and version within 2 seconds And Party B’s corresponding field reflects the new value within 2 seconds with a 'Synced' indicator And the change is idempotent when the same value is submitted again
Field-Level Provenance and Audit Trail
Given any change to a shared field When the change is saved Then a provenance record is written containing field path, prior value, new value, source questionnaire (Petitioner/Respondent), actor ID, channel, ISO-8601 UTC timestamp, and change reason (optional) And the provenance record is immutable and retrievable via the matter audit log And querying the audit log by field path returns the complete chronological history
Shared Entity Deduplication and Canonicalization
Given both parties enter a child with matching DateOfBirth and name similarity >= 0.9 (case- and accent-insensitive) When the second entry is saved Then the engine merges into a single canonical Child entity with both sources linked and no duplicate appears in the common fact set And if multiple candidate matches exist or similarity < 0.9, the new entry is held for review and not auto-merged And addresses are normalized (USPS/CAN formats) and deduplicated by normalized Line1+PostalCode; exact matches auto-merge, partial matches require review
Auto-Merge vs Review Gate Based on Configurable Rules
Given the merge policy for Child.DateOfBirth is set to Auto-Merge When either party updates Child.DateOfBirth Then the canonical value updates immediately and both questionnaires reflect the change within 2 seconds Given the merge policy for Address.Line1 is set to Require Review on cross-party change When the opposing party changes Address.Line1 Then a review item is created with before/after values and source, the canonical value remains unchanged, and both questionnaires show 'Pending review' on that field And approving applies the change and syncs within 2 seconds; rejecting discards it and records the decision in the audit log
Propagation to Matter Record, Conflict Checks, and Document Assembly
Given a canonical shared field (e.g., HomeAddress) changes When the change is committed (auto-merge or approved) Then the matter record reflects the new value immediately And conflict screening re-runs within 5 seconds using the updated value and logs the result And any draft documents using the field are marked 'Stale' within 5 seconds and the next generation uses the updated value without manual re-entry
Concurrent Edit Resolution and User Feedback
Given Party A and Party B submit different values for the same shared field within a 10-second window When both saves are received Then the engine detects a conflict, creates a single review item with both proposed values and timestamps, and leaves the canonical value unchanged And both questionnaires display a non-blocking 'Conflict pending review' notice on the field And if both proposed values are identical, the engine records a single update with combined provenance (no review required)
Partitioning of Shared vs Party-Specific Fields
Given fields are tagged as Shared or Party-Specific in the schema When a Party-Specific field (e.g., PartyA.Income) is entered by one party Then it does not appear in the other party’s questionnaire nor in the canonical shared fact set And when a Shared field (e.g., Child.School) is entered by either party Then it syncs to the canonical set and the other questionnaire according to merge policies
Party-Specific Data Partitioning & Access Controls
"As an attorney, I want party-specific responses kept separate and permissioned so that sensitive information isn’t exposed to the other party or unauthorized staff."
Description

Enforces strict segregation of party-specific responses while allowing designated shared fields to flow into the common fact set. Implements role-based access controls, field-level permissions, and encryption to ensure only authorized firm users can view or edit sensitive disclosures. Includes configurable visibility rules, secure sharing links, and audit logs to meet confidentiality and ethical obligations while enabling streamlined intake. Integrates with CaseSpark user management and matter permissions.

Acceptance Criteria
Prevent Cross-Party Visibility of Responses
Given a matter with two parties using MirrorSync questionnaires And party-specific fields configured for each party When Party A submits party-specific responses Then users assigned to Party B or unassigned roles cannot view Party A's responses in UI, exports, or API And direct access to Party A response IDs returns HTTP 403 with no data leakage And the access denial event is recorded in the audit log with user, role, time, and endpoint
Shared Field Sync into Common Fact Set
Given fields designated as shared (e.g., children, addresses, dates) And both parties have independent questionnaires When either party updates a shared field Then the common fact set reflects the latest value with source party and timestamp metadata And the counterparty's raw entry remains hidden from users without "View Both Parties" permission And conflicting values trigger a "Needs Review" status visible only to authorized roles, without revealing the counterparty's text to unauthorized users And changes to party-specific fields never modify the common fact set
Role-Based Access Control Enforcement
Given CaseSpark user management and matter-level permissions (Owner, Attorney, Paralegal, Intake) And a role-permission policy for view/edit/export by field category When a user attempts to view or edit party-specific or shared fields Then access is granted or denied strictly per role and matter assignment, returning HTTP 403 for unauthorized operations And role or assignment changes take effect within 60 seconds across UI and API And all grant, revoke, and permission changes are captured in the audit log with actor, target, and before/after values
Field-Level Visibility and Masking
Given field-level rules configured as view, edit, hidden, or masked per role When a user with "masked" access opens a record Then the UI displays placeholders (e.g., ••••) and the API omits plaintext values, returning only metadata And users with "hidden" access do not receive the field in UI or API payloads And switching a user's role immediately updates visibility without requiring logout
Secure Party Questionnaire Links
Given a secure sharing link is generated for a party's questionnaire And link policy requires email verification and one-time SMS OTP When the recipient accesses the link within its validity window Then access is granted only after successful verification, and responses are saved to that party's partition And the link expires upon first completion or after the configured TTL, whichever comes first And attempts to reuse or access from a different party or matter return HTTP 403 and are audit-logged
Encryption of Sensitive Data
Given storage of party-specific responses, shared fact set, and audit logs When data is written to persistent storage Then it is encrypted at rest with AES-256 or stronger using a managed KMS And all data in transit uses TLS 1.2+ with HSTS enabled for web clients And encryption keys are rotated at least every 90 days and never exposed in logs And plaintext sensitive values never appear in application logs or analytics events
Audit Trail Completeness and Integrity
Given any access, change, export, or permission update related to party-specific or shared fields When the event occurs Then an audit record captures actor identity, role, party context, action, target field(s), timestamp (UTC), IP, client, and outcome (success/denied) And for content changes, before/after values are captured with sensitive fields masked per policy And audit logs are immutable, queryable by matter and date range, exportable to CSV, and retained for at least 7 years And tampering attempts or log write failures generate alerts to system admins within 5 minutes
Jurisdiction-Aware Branching Rules Library
"As a paralegal, I want the questionnaire to branch based on jurisdiction-specific requirements so that we collect exactly what each court needs without unnecessary questions."
Description

Provides a centrally managed rules library that determines question flow by jurisdiction, court, and case subtype. Supports versioning, effective dates, testing sandboxes, and rollback. Offers an editor for legal ops to author and maintain branching logic without code, with validation and preview against sample matters. Integrates with CaseSpark’s knowledge base and document assembly variables so collected data matches court-specific requirements and updates can be deployed rapidly across forms.

Acceptance Criteria
Branch Flow Selection by Jurisdiction/Court/Case Subtype
Given a matter with jurisdiction="CA", court="Los Angeles Superior Court", caseSubtype="Uncontested Divorce", filingDate="2025-10-01" When the rules engine resolves the question flow Then it selects the active rule set matching (CA, Los Angeles Superior Court, Uncontested Divorce) effective on 2025-10-01 and returns a flow ID and first question Given a matter with jurisdiction="CA", court="Unknown Court", caseSubtype="Uncontested Divorce" When resolving Then it falls back to the most specific available rule set (CA, *, Uncontested Divorce) and logs a WARN event "COURT_RULE_MISSING" with the matter ID Given no applicable rule set exists When resolving Then the engine returns error code "RULESET_NOT_FOUND" and no flow is started Given a resolved flow for the same inputs When re-evaluated Then the outcome is deterministic and identical
Rule Versioning with Effective Dates and Rollback
Given three versions of a rule set with non-overlapping effective date windows When evaluating a matter whose filing date falls within v2's window Then v2 is applied regardless of publish date Given an administrator performs a rollback of a rule set from v3 to v2 in Production When the rollback is confirmed Then new evaluations route to v2 within 2 minutes and an audit log entry records user, timestamp, fromVersion, toVersion Given in-flight matters bound to v3 When a rollback occurs Then they continue using v3 unless explicitly re-bound by a user action "Re-evaluate Flow" Given overlapping effective date windows are created in the editor When attempting to publish Then publication is blocked with validation error "EFFECTIVE_DATE_OVERLAP"
Sandbox Drafting and Promotion Workflow
Given a draft rule set saved to Sandbox When previewing a sample matter Then the Sandbox version is used and Production remains unchanged Given promotion criteria require at least 1 reviewer approval and all automated tests pass When a maintainer requests promotion Then promotion is blocked until approvals are granted and the test suite status is Pass Given a promotion completes When monitoring telemetry Then no Production evaluations receive HTTP 5xx during the deployment window and version tag updates are visible via API within 60 seconds
No-Code Rule Editor with Validation and RBAC
Given a Legal Ops user with Editor role When authoring conditions Then operators (equals, in, contains, regex, date range) and targets (jurisdiction, court, case subtype, party role) are selectable via UI without code input Given a rule graph containing cycles, unreachable nodes, or dangling variable references When running validation Then save is blocked and all issues are listed with node IDs and line references Given a user without Editor role When attempting to modify Production rules Then access is denied with HTTP 403 and the UI is read-only Given a valid change When saving Then a new minor version is created with semantic versioning (e.g., 2.3.1) and change notes are required
Preview Against Sample Matters and Variable Binding Integrity
Given a sample matter and selected jurisdiction/court/subtype When preview is run Then the exact question sequence is displayed and a coverage report shows 100% of required court variables are bound Given a branching rule maps to a document assembly variable not present in the knowledge base When validating Then an error "UNKNOWN_VARIABLE" is raised and publish is blocked Given switching preview context from Party A to Party B in MirrorSync When viewing shared fields Then shared variables appear once with a common fact-set tag, and party-specific questions remain partitioned
Production Propagation and Performance SLAs
Given a new rule set is promoted to Production When querying a linked intake form via API Then the form consumes the new logic within 5 minutes without service restart Given existing matters mid-intake When a new rule set is promoted Then they continue on their bound version unless a user opts to upgrade, preserving all entered answers Given 10,000 rule evaluations over 15 minutes under normal load When measuring latency Then 95th percentile evaluation time is <= 300 ms and error rate is < 0.5% Given a rollback or promotion event When checking audit logs Then entries include actor, environment, reason, version diff hash, and timestamp
Neutral Language Template Pack
"As an intake coordinator, I want non-adversarial language across both questionnaires so that clients feel safe and the process remains impartial."
Description

Delivers a curated set of neutral, non-adversarial phrasing templates and a tone checker that lint questions and help text for adversarial or biased wording. Supports inclusivity, plain language at appropriate reading levels, and multilingual variants where available. Applies consistent style guidance across mirrored questionnaires and flags deviations during form authoring. Integrates with the intake builder so teams can adopt or customize templates at scale.

Acceptance Criteria
Inline Tone Checker in Intake Builder
Given I am authoring a question or help text in Intake Builder. When the text includes phrases matching adversarial or biased rules from the Neutral Language Template Pack and I pause typing for 300ms or blur the field. Then the tone checker underlines each offending phrase, labels it with category and severity, and displays at least one neutral suggestion per phrase. And one-click replacement preserves variable placeholders and formatting. And phrases on the workspace whitelist are not flagged. And the lint issue count in the sidebar updates within 100ms of detection or fix.
Apply Neutral Templates to Mirrored Questionnaires
Given a neutral language template is applied to a mirrored question group. When the system generates both party versions. Then both question texts are neutral and identical except for role tokens and allowed role-specific placeholders. And shared fields bind to a common fact key across parties. And party-specific prompts remain partitioned and do not write to the common fact key. And manual edits to either side are linted for neutrality and produce deviation warnings if style guidance is violated. And the side-by-side preview shows no textual divergence beyond role tokens.
Reading Level Compliance Lint
Given the project plain-language threshold is set to Flesch–Kincaid Grade Level 8 by default. When I run Lint on the questionnaire. Then each question and help text displays a computed grade level score. And any item exceeding the threshold is flagged with a "Plain Language" warning and included in the summary count. And changing the threshold to Grade 6 updates flags and counts in real time without page reload. And items marked as "Legal Term of Art" are exempt and appear as waived with recorded reason.
Inclusivity and Bias Language Detection
Given the Inclusivity Lexicon and guidance rules are enabled for the workspace and jurisdiction. When authored content contains terms that match Inclusivity Lexicon entries that are not marked as Required by Jurisdiction. Then the lint flags each term with category "Inclusivity" and provides a neutral alternative from the template pack. And accepting a suggestion updates both mirrored sides consistently where applicable. And if a term is legally required for the selected jurisdiction, the system allows an exception with a documented reason and suppresses further flags for that instance.
Multilingual Variants and Fallback
Given the workspace locale is set to Spanish (es) and a multilingual neutral template exists. When I apply the template to a mirrored questionnaire. Then generated content appears in Spanish with correct placeholders and role tokens, and both party versions remain textually equivalent. And where a Spanish variant is missing, the English text is used and a "Missing Variant" warning appears in the lint summary. And switching the locale back to English re-renders the content in English without breaking fact bindings or role tokens. And reading-level checks run against the selected language using the configured threshold for that language.
Cross-Form Style Consistency Report
Given the style guide includes rules for capitalization of defined terms, contractions, and punctuation. When I run Style Check across both mirrored forms. Then all deviations are listed with rule IDs, locations, and suggested fixes. And the total deviation count is zero before publish or all deviations are explicitly waived with reasons. And the downloadable CSV report matches on-screen counts and details. And fixing or waiving an item updates the report and counts within 1 second.
Template Pack Adoption and Customization
Given I have Admin role in the workspace. When I duplicate the Neutral Language Template Pack, edit templates, and publish version 2.0. Then new forms created after publish default to version 2.0. And existing forms can opt in via an Upgrade flow that shows a diff preview and supports bulk auto-merge of non-conflicting changes. And all publish, upgrade, and rollback actions are recorded in an audit log with author, timestamp, and change summary. And rolling back to version 1.0 restores prior content without breaking fact bindings or mirrored role tokens. And non-admin users cannot publish or change global thresholds.
Conflict Resolution & Audit Trail for Divergent Facts
"As an attorney, I want to see and resolve conflicting responses between parties so that our filings reflect accurate facts and clearly mark disputed information."
Description

Detects and flags discrepancies when parties provide conflicting answers on shared fields, surfaces a side-by-side compare view, and provides resolution workflows (accept one value, mark as disputed, or request clarification). Maintains a full audit trail with timestamps, authorship, and rationale, and pushes the resolved or disputed status into document assembly with appropriate annotations. Supports notifications and tasks for staff to follow up on unresolved conflicts.

Acceptance Criteria
Automatic Conflict Detection on Shared Fields
Given both parties have submitted responses to a shared field And the system has normalized values (trimmed whitespace, case-insensitive comparison, standardized date/phone/address formats) When the normalized values differ Then the field is flagged as Conflict within 2 seconds of the second submission And the matter dashboard displays an incremented conflict count for the case And both raw and normalized values are stored with party attribution And if the normalized values match Then the field is marked In Agreement and no conflict is created
Side-by-Side Compare View Rendering
Given a case with at least one conflicted shared field When a user with access opens the compare view Then the system displays both parties' values side by side with clear party labels And highlights differing tokens (word-level for text, component-level for dates/addresses/phones) And shows last-updated timestamps and authorship for each value And allows filter by category (e.g., Children, Addresses, Financial) and sort by recency/severity And loads the view in under 1.5 seconds for up to 200 conflicted fields
Resolution Workflow: Accept, Dispute, Clarify
Given a conflicted field is open in the compare view When a staff user selects Accept Party A or Accept Party B Then the common fact set is updated with the chosen value and status Resolved And the action requires a rationale (minimum 10 characters) And the system stores resolver, timestamp, and preserves previous values in the audit trail When a staff user selects Mark as Disputed Then the fact status is set to Disputed with a required reason And the document assembly receives a disputed flag with the field identifier When a staff user selects Request Clarification (party A, party B, or both) Then a clarification task is created with a default due date of 3 business days and templated message And notifications are sent to selected recipients And the field status is set to Pending Clarification And any resolution action can be reverted, creating a new audit version
Audit Trail Completeness and Export
Given conflict detection, view, resolution, dispute, clarification, or revert events occur When any such event is saved Then an immutable audit entry is recorded with UTC timestamp, actor (user or party), action type, prior value(s), new value (if applicable), rationale (if provided), and source IP/device for party submissions And audit entries are viewable inline for each field and filterable by field, actor, and date range When a user exports the audit trail for the case Then a paginated PDF and JSON export are generated within 5 seconds for up to 500 events (server-side queued beyond that) And each export includes a tamper-evident checksum that can be verified via an endpoint returning Valid or listing mismatches
Propagation to Document Assembly
Given a conflicted field is resolved to a single value When the resolution is saved Then the document assembly service is updated within 1 second with the resolved value and status Resolved And generated documents use the resolved value with no dispute annotations Given a field is marked Disputed When documents are generated for three supported jurisdictions Then annotations follow jurisdiction-aware rules (inline bracket, footnote, or margin note per template settings) And the disputed annotation includes the field label and optional brief rationale (<= 120 characters) Given a field is Pending Clarification When a user attempts document generation Then the system warns of placeholders and blocks generation if the template marks the field as required for filing
Notifications and Tasking for Unresolved Conflicts
Given a conflict is detected on a case When detection occurs Then a task is created for the Intake Specialist role with a default due date of 2 business days And an in-app and email notification are sent to the assignee(s) within 30 seconds When a conflict remains unresolved 48 hours before the matter deadline Then an escalation notification is sent to the attorney of record and the matter shows a Needs Attention banner And notifications are rate-limited to at most one per 4 hours per recipient per conflicted field state change When all conflicts are Resolved or Disputed Then the matter readiness indicator updates to Clear to Assemble within 10 seconds
Custom Field Mapping & Admin Controls
"As a firm owner, I want to configure what data is shared or partitioned so that MirrorSync aligns with our workflows and ethics obligations."
Description

Allows admins to declare which fields are shared versus party-specific, define mappings between mirrored forms, and configure validation and requiredness rules. Provides schema import/export, environment-based configuration (dev/stage/prod), and change review to safely roll out updates. Integrates with CaseSpark’s intake and document variable schemas so that data flows predictably from questionnaires into the common fact set and downstream filings.

Acceptance Criteria
Shared vs Party-Specific Behavior
Given I am an admin in the MirrorSync admin console in the Dev environment And a field "children.primary_address" exists in the questionnaire schema When I mark "children.primary_address" as Shared and save a draft Then the draft version records "children.primary_address" with classification "shared" When the draft is approved and deployed to Dev And the petitioner enters a value for "children.primary_address" And the respondent subsequently opens their questionnaire Then the respondent sees "children.primary_address" pre-populated from the common fact set And updates by either party to "children.primary_address" synchronize bidirectionally into the common fact set within 2 seconds And the value is not displayed in the opposite party’s answer history or audit panel beyond the common fact set value And if the two parties submit conflicting values for "children.primary_address" within the same version Then the field is flagged "needs_review" per the configured reconciliation policy and is not propagated downstream until resolved And a field "employment.employer_name" marked Party-Specific stores values in separate party partitions and never syncs into the shared common fact set
Jurisdiction-Aware Branching Rules
Given I configure a branching rule: If jurisdiction == "CA" then show field "marriage.date_of_separation" as Required; else hide When I create a case with jurisdiction "CA" Then both mirrored questionnaires include "marriage.date_of_separation" as a required field And attempting to submit either party’s questionnaire without this field produces a blocking error message referencing the field label When I create a case with jurisdiction "NY" Then "marriage.date_of_separation" is not rendered for either party and is not required And the stored schema evaluation log records the rule evaluation outcome for each party
Validation and Requiredness Configuration
Given I configure validation: "children.count" must be an integer >= 0; "child[].dob" must be a past date; and requiredness: if "has_children" == true then require at least one "child[]" When the respondent enters "children.count" = -1 Then an inline error appears immediately and form submission is blocked until a valid value is provided When the petitioner enters a future date for "child[0].dob" Then an inline error appears referencing acceptable formats and past-date constraint When "has_children" == true for either party and no child records exist Then submission is blocked with an error listing missing required fields And when "has_children" == false Then all child-related fields are optional and hidden And all validation and error messages render in neutral, non-adversarial language And server-side validation enforces the same rules upon submission and returns structured errors with field paths
Schema Import/Export with Validation & Diff
Given I export the current Dev schema Then a versioned JSON file with a semantic version, createdAt timestamp, and checksum is downloaded When I import a schema file with an unknown field type or invalid mapping reference Then the import is rejected in dry-run mode with a list of line-numbered errors and no changes applied When I import a valid schema file in dry-run mode Then a diff is displayed showing added/changed/removed fields, rules, and mappings When I confirm apply Then the schema version increments and the changes are persisted And a rollback point is created referencing the prior version and checksum
Environment Segregation & Promotion Gates
Given separate configurations exist for Dev, Stage, and Prod When I edit mappings in Dev Then no changes appear in Stage or Prod until explicitly promoted When I attempt to promote a Dev version to Stage that deletes a field mapped to an active Prod document variable Then the promotion is blocked with a "breaking change" error listing impacted variables and documents When promotion from Dev to Stage succeeds Then the exact version number and checksum appear in Stage and are immutable And environment-specific secrets or endpoints are not overwritten during promotion
Change Review, Versioning & Audit Trail
Given I have "Config Editor" role and create a draft with changes to shared/party flags and validations Then the draft is pending review and cannot be deployed without approval by a user with "Config Approver" role When an approver reviews the draft Then a side-by-side diff is shown and they can Approve or Request Changes with comments When approved and deployed Then the system records an audit entry with who, when, version, checksum, and a summary of changed objects And I can roll back to any prior version, restoring its exact checksum and configuration And all review comments are preserved and linked to the deployed version
Integration with Intake & Document Variable Schemas
Given the intake question schema and the document variable schema are loaded And I map questionnaire fields to document variable identifiers (e.g., common_fact.children[i].name -> doc.children[i].name) When I run a preflight on the current schema for a selected filing package Then the system reports any unmapped required document variables and blocks deployment until resolved or marked "not_applicable" with justification When both parties complete their questionnaires without validation errors Then the common fact set is populated according to shared/party-specific rules And the downstream document assembly receives the expected values for all mapped variables And any variables marked "not_applicable" remain unset in the assembled document

Fact Harmonizer

Auto‑detect contradictions, show side‑by‑side differences, and propose a reconciled value with confidence notes (e.g., date proximity, document support). One‑tap accept/flag flows let both parties or a mediator resolve items quickly, turning friction into clear, agreed facts.

Requirements

Contradiction Detection Engine
"As a solo attorney, I want the system to automatically detect contradictory facts across client inputs and documents so that I can quickly identify and resolve inconsistencies before drafting filings."
Description

Implements real-time detection of inconsistent facts across all intake channels (guided forms, call transcripts, uploads, prior matters, and synced sources). Normalizes entities (names, addresses, dates, monetary amounts, custody terms) and applies fuzzy matching, tolerance windows, and pattern rules to identify contradictions and near-matches. Runs incrementally as new data arrives, surfaces structured conflict items with rationale, and exposes results via internal services for UI, notifications, and downstream automation within CaseSpark.

Acceptance Criteria
Real-Time Cross-Channel Detection in Guided Intake
Given a user is completing a guided-intake step and enters a new fact for an entity attribute When the field is saved (blur or step advance) Then contradictions and near-matches against all indexed sources (prior matters, synced sources, uploads, transcripts) are evaluated within 300 ms p95 Given evaluation completes and contradictions are found When emitting results Then at most one conflict item per entity-attribute is produced with classification (contradiction|near-match) and linked source IDs Given no contradictions or near-matches are found When evaluation completes Then no conflict item is emitted and no UI notification is triggered Given multiple conflicting sources for the same attribute When emitting the item Then all conflicting sources are aggregated into the item and a source_count is included
Incremental Detection on Streaming and Upload Events
Given a new transcript chunk yields an extracted fact When it is ingested Then only impacted entity-attributes are re-evaluated and processing completes within 1 s p95 from ingestion time Given a document upload finishes parsing When new facts are extracted Then corresponding conflict items are created or updated within 5 s p95 from parse completion Given a newer, higher-priority source provides a value that supersedes a conflicted value When detected Then the prior conflict item is updated to status=resolved and a resolution event is emitted within 2 s
Entity Normalization and Canonicalization
Given variant inputs for names, addresses, dates, monetary amounts, and custody terms When normalized Then outputs conform to canonical formats: PersonName (First Middle Last), Address (standardized lines + postal code), Date (ISO-8601 with timezone), Money (ISO currency code + decimal), CustodyTerm (taxonomy key) Given the normalization test fixtures are executed When evaluated Then normalization accuracy is >= 98% and uncertain cases are <= 1% Given normalization fails validation When encountered Then the fact is quarantined (excluded from contradiction detection) and an error event with reason code is emitted
Fuzzy Matching and Tolerance Windows
Given two dates for the same event When absolute difference <= 2 days Then classify as near-match; when > 2 days, classify as contradiction Given two monetary amounts in the same currency When relative difference <= 2% or absolute difference <= 50 Then classify as near-match; otherwise classify as contradiction Given person names for the same party When Jaro-Winkler similarity >= 0.92 or alias mapping matches Then treat as same canonical entity; when 0.85–0.92, flag as near-match; when < 0.85 and asserted equal, classify as contradiction Given postal addresses When normalized strings have Levenshtein distance <= 3 and same postal code Then classify as near-match; otherwise classify as contradiction Given custody terms When taxonomy buckets differ Then classify as contradiction; when within same bucket with minor wording differences, classify as near-match Given tenant-level tolerance overrides exist When evaluation runs Then custom thresholds are applied and recorded in rationale notes
Structured Conflict Item with Rationale and Confidence
Given a contradiction or near-match is detected When emitting the conflict item Then payload includes: item_id, matter_id, entity_type, entity_id, attribute, observed_values[], normalized_values[], source_refs[] (channel,type,source_id,timestamp), classification, metrics (delta or similarity), confidence [0,1], proposed_reconciled_value, rationale_notes[], created_at, updated_at Given sources differ in recency and document support When computing confidence Then rationale_notes include at least one of: "more recent by N days", "document-backed", or "from synced source X", and confidence reflects weighted factors Given duplicate detections for the same entity-attribute within 10 minutes When producing output Then items are deduplicated by (entity-attribute, normalized values set) and only updated_at is advanced Given schema validation runs in CI and at runtime When a payload is produced Then it validates against the published JSON Schema with 100% pass rate
Internal Services Exposure and Availability
Given an authenticated request to GET /v1/contradictions?matter_id={id} When the matter has conflict items Then the API returns 200 with paginated items, filterable by classification and entity_type, within 200 ms p95 Given conflict items are created, updated, or resolved When state changes Then events contradiction.created, contradiction.updated, and contradiction.resolved are published within 500 ms p95 of the change Given a caller lacks the contradictions:read scope When requesting the API Then the API returns 403 and no conflict data is returned Given a request has invalid parameters When validation fails Then the API returns 400 with machine-readable error codes Given service reliability is measured over a rolling 30 days When computing SLIs Then availability is >= 99.9% and 5xx error rate is <= 0.1%
Side-by-Side Fact Diff Viewer
"As an intake paralegal, I want a clear side-by-side view of conflicting facts with source context so that I can understand what differs and why without digging through multiple screens."
Description

Provides a split-view UI that displays conflicting values with standardized labels, highlights differences at the field and token level, and shows source context (who provided it, when, and from which document or step). Supports search, filters, pagination, and accessibility standards. Integrates with CaseSpark’s intake workspace so users can review conflicts without leaving the flow, and can be embedded in client and mediator portals.

Acceptance Criteria
Split-View Diff with Standardized Labels and Source Context
Given a conflict between two values for the same canonical field, When the viewer loads, Then a two-pane split view is rendered with the canonical field label displayed once above both panes. Given two differing values, When displayed, Then differences are highlighted at both field level and token level (insertions, deletions, substitutions) with a visible legend. Given the conflict's provenance, When shown, Then the source context displays provider name and role, timestamp (ISO 8601, localized), and origin (document name or intake step) with a clickable drill-through link. Given raw field names differ (e.g., "DOB" vs "Birth Date"), When rendered, Then the label shown is the standardized canonical name from the data model. Given a date, number, or address, When token-level diff is applied, Then tokens respect domain-aware units (YYYY-MM-DD components, digit groups, address components) to reduce false positives. Given one side has no value, When rendered, Then the UI indicates "No value provided" without error.
Search, Filter, and Sort Across Conflicts
Given a set of conflicts, When a user enters a search term, Then conflicts are filtered by matches in field label, values, and source context within 300ms for up to 500 conflicts. Given filters (party/role, source type, conflict type, status, date range, confidence), When applied, Then only matching conflicts remain and active filter chips with counts are shown. Given a sort option is selected (field name A→Z/Z→A, newest/oldest source timestamp, highest/lowest confidence), When applied, Then the list reorders accordingly and the sort direction is indicated. Given no results match search/filters, When rendered, Then an empty state appears with a clear-all action that restores the previous list.
Pagination and State Preservation with Performance Targets
Given more conflicts than the page size, When the viewer loads, Then it shows 25 conflicts per page by default, displays total count, and renders pagination controls with current/total pages. Given a user navigates via next/previous or a specific page number, When activated, Then the view updates without a full page reload and preserves active search, filters, and sort. Given a dataset up to 1,000 conflicts, When paging or searching, Then initial time-to-interactive is ≤ 1,000ms and subsequent page/search updates are ≤ 500ms on reference hardware. Given the user uses the browser back/forward buttons, When triggered, Then the viewer restores the same list state (page, search, filters, sort) as before navigation.
Accessibility: WCAG 2.1 AA, Keyboard Navigation, and Screen Readers
Given keyboard-only use, When navigating the viewer, Then the user can move focus among conflicts, panes, filters, and pagination using Tab/Shift+Tab and arrow keys; Enter/Space activates controls; visible focus is present on all interactive elements. Given a screen reader (e.g., NVDA/JAWS/VoiceOver), When reading a conflict, Then it announces the canonical field label, a concise difference summary, and source context using appropriate roles and ARIA attributes. Given color-blind accessibility, When diff highlights are shown, Then contrast ratio is ≥ 4.5:1 and differences are communicated by more than color (e.g., underline/pattern/icons). Given zoom up to 200%, When applied, Then content remains usable without loss of information or horizontal scrolling at 1280px width.
Intake Workspace Integration and Deep-Linking
Given a user is completing an intake, When "View Conflicts" is selected, Then the viewer opens in-place (drawer or modal) without leaving the intake flow, and the intake form state is preserved. Given the viewer is closed, When dismissed, Then the user returns to the same scroll position and any unsaved intake changes remain intact. Given a deep link to a specific conflict exists (e.g., from a validation message), When opened, Then the viewer scrolls to and focuses that conflict with its context expanded. Given role-based permissions, When the viewer loads, Then only conflicts the user is authorized to see are displayed; restricted source details are redacted per policy.
Embeddable Viewer for Client and Mediator Portals
Given the viewer is embedded in a client or mediator portal, When rendered, Then it loads via a secure component (iframe or Web Component) that enforces allowed origins and CSP. Given an authenticated portal session, When the viewer initializes, Then it exchanges SSO tokens and enforces role-based redactions (e.g., hide opposing party source details as configured). Given responsive constraints, When viewport width ranges from 320px to 1920px, Then the split view adapts (stacked on narrow screens) while preserving token-level highlights and tap targets ≥ 44x44 px. Given host theming variables are provided, When applied, Then the viewer adopts host typography and colors without violating accessibility contrast requirements.
Reconciliation Proposals & Confidence Notes
"As a mediator, I want the system to suggest a best-fit fact with explanations so that I can make informed decisions quickly."
Description

Generates a proposed reconciled value for each conflict, accompanied by a confidence score and explanatory notes (e.g., document-backed, recency advantage, jurisdiction rule alignment, date proximity). Supports alternative suggestions when confidence is low and explains tradeoffs. Writes chosen outcomes into the canonical case fact model and logs rationale for auditability within CaseSpark.

Acceptance Criteria
Proposal Generation with Confidence and Notes
Given a case fact has at least two conflicting source values When the Fact Harmonizer processes the conflict Then it must generate a single proposed reconciled value And it must display a numeric confidence score between 0 and 100 And it must include at least two applicable explanatory notes from {document-backed, recency advantage, jurisdiction rule alignment, date proximity} And it must display the conflicting source values and the proposal side-by-side with source labels And proposal generation must complete in under 2 seconds per conflict
Low-Confidence Alternatives and Tradeoffs
Given a proposed reconciliation has a confidence score below 60 When the proposal is presented to the user Then the system must present at least one alternative suggestion with a distinct value And each alternative must include tradeoff notes stating at least one reason (e.g., missing document support, older source, cross-field inconsistency, jurisdiction mismatch) And one-tap actions must be available to Accept Proposal, Accept Alternative, or Flag for Review And choosing any action must complete in under 1 second after confirmation
Write-Through to Canonical Model and Audit Log
Given a user with edit permission accepts a proposal or an alternative When the acceptance action is confirmed Then the chosen value must be written to the canonical case fact model with a new version id And the write must store: chosen value, conflicting values with source ids, confidence score at decision time, selected notes, actor id, and UTC timestamp (ISO 8601) And an immutable audit log entry must be appended capturing action type and rationale notes And the audit entry must be retrievable in the case audit viewer within 2 seconds And end users must be unable to modify or delete existing audit entries
Flag-for-Review Workflow
Given a user flags a proposed reconciliation for review When the flag action is submitted Then the item must enter the Review queue with status "Needs Reconciliation" And a reason/comment of at least 10 characters must be required And the item must be auto-assigned per case reviewer settings And notifications to assignees must be sent within 60 seconds And the fact must not be written to the canonical model until a decision is made
Jurisdiction Rule Alignment Note and Citation
Given the case jurisdiction is set and a relevant rule mapping exists for the fact type When the proposal and confidence notes are generated Then a "jurisdiction rule alignment" note must be included indicating alignment or conflict And the note must include the jurisdiction code and a human-readable rule citation or id And activating the note must open the rule reference details in-app And if no rule mapping exists, no jurisdiction note is shown and confidence is calculated without that factor
Retry and Failure Behavior
Given an internal error occurs during proposal generation for a conflict When the error is detected Then the user must see a clear message and a Retry action And a detailed error record with trace id, operation, timestamp, and non-PII context must be written to the audit log And no partial data must be written to the canonical fact model And selecting Retry must reattempt generation and update the UI state on success or failure
One-Tap Accept/Flag Resolution Flow
"As a client, I want to accept or flag a proposed fact with one tap so that we can move the intake forward without lengthy back-and-forth."
Description

Enables concise actions to accept a proposal, select a source value, enter a manual correction, or flag for follow-up—individually or in bulk. Supports two-party acknowledgment flows and mediator override with reason capture. Creates an immutable audit trail, posts updates to the case timeline, triggers tasks and notifications, and enforces role-based permissions within CaseSpark’s user management.

Acceptance Criteria
One-Tap Accept of Reconciled Value
Given a user with Edit Facts permission views a contradiction item with a proposed reconciled value When the user taps Accept on the item Then the fact value is updated to the proposed value and the item status becomes "Resolved – Accepted Proposed" And an immutable audit record is created capturing: item ID, prior values, accepted value, decision type, user ID, role, timestamp (UTC ISO-8601), client IP/UA, action source (UI/API), and confidence notes snapshot And a case timeline entry is posted with a human-readable diff and link to the item And notifications are sent to subscribed watchers and counterparties per notification rules And the UI refreshes to show the resolved state within 800 ms (p95) on a wired connection And users without Edit Facts permission are blocked with a 403 error and no changes are persisted
Bulk Accept/Flag Actions
Given a user with Edit Facts permission selects between 2 and 200 contradiction items in the Fact Harmonizer When the user triggers a bulk Accept or bulk Flag action Then each item is processed independently and results are summarized as counts of Succeeded, Skipped, and Failed with per-item reasons And successful items create audit records and timeline entries exactly as their single-item counterparts And failed items do not affect successful items; no partial writes occur within an item And the bulk operation completes within 5 seconds (p95) for 100 items and within 10 seconds (p95) for 200 items And the UI provides an exportable CSV of per-item outcomes And users without bulk-action permission are blocked with a 403 and no items are processed
Select Source Value as Resolution
Given a contradiction item displays two or more source values with provenance (e.g., Party, Document ID) When the user selects "Resolve by Source" and chooses a specific source value Then the resolved fact is set to the selected value and the item status becomes "Resolved – Selected Source" And the chosen source’s provenance (party, document ID/version) is stored and displayed And type validation is enforced (e.g., date, currency, integer); invalid selections are blocked with inline error messaging And an immutable audit record and case timeline entry are created referencing the selected source and the diff from prior values And notifications and dependent task triggers fire according to configured rules
Manual Correction Entry with Validation
Given a user needs to correct a contradiction item with a value not present in sources When the user selects "Manual Correction," enters a new value, and provides a required reason (min 10 characters) and optional supporting document/link Then the input is validated against field rules (format, range, length, locale/date rules, currency precision) And on success the item status becomes "Resolved – Manual Correction" and the corrected value is applied And the reason and any attachments are stored and visible in the item history And an immutable audit record and timeline entry are created including the reason text and attachments And invalid input prevents save with specific inline errors and no side effects
Two-Party Acknowledgment Flow
Given a matter is configured for two-party acknowledgment and an item is in a resolvable state When Party A accepts a resolution (accept proposed, select source, or manual correction) Then the item status becomes "Pending Counterparty" and Party B is notified via in-app and email When Party B accepts within 7 calendar days Then the item status becomes "Acknowledged by Both" and a joint acknowledgment timeline entry is posted When Party B flags instead of accepting Then the item status becomes "Contested" and a follow-up task is created for the assigned attorney When the 7-day window expires without Party B action Then the item status becomes "Expired – Requires Follow-up" and a task and reminder notification are issued And all acknowledgments/flags are captured as separate audit entries per party with user ID, role, timestamp, and decision
Mediator Override with Reason Capture
Given a user with Mediator role views an item in Pending Counterparty or Contested status When the mediator selects Override, enters a mandatory reason (min 10 characters), and confirms Then the item status becomes "Resolved by Mediator" and further party edits are blocked unless the mediator reopens the item And both parties receive notifications including the mediator’s reason And an immutable audit record captures the override action, mediator identity, reason, and before/after values And a timeline entry is posted indicating mediator resolution
Immutable Audit Trail and Timeline Posting
Given any resolution action (accept, select source, manual correction, flag, acknowledgment, override) occurs Then an append-only audit record is written and cannot be edited or deleted by any role; attempted modifications are denied and logged as security events And the audit record includes: item ID, action, actor user ID, role, timestamp (UTC ISO-8601), before values, after value, resolution type, reason (if any), related document IDs/versions, confidence notes snapshot, actor IP/UA, and correlation ID And a case timeline entry is posted within 2 seconds (p95) containing a readable summary and link to the item And the reporting API can retrieve audit records by item ID and date range, returning results within 1 second (p95) for up to 1,000 records
Source Provenance & Trust Scoring
"As an attorney, I want to see which source a fact came from and how reliable it is so that I know when to rely on it in filings."
Description

Captures and displays detailed provenance for each fact (input channel, document type, signer identity, notarization/verification state, upload hash, timestamp) and computes configurable trust weights that influence proposal confidence. Exposes provenance in the UI and via API, supports integration with document verification services, and allows firm-level tuning of weights and policies in CaseSpark settings.

Acceptance Criteria
UI Provenance Display for Fact Card
Given a fact with two contributing sources (web intake form and notarized PDF), When the user opens Fact Harmonizer and expands the fact's details, Then for each source the UI displays: input channel, document type, signer identity, verification/notarization state, upload hash, and timestamp. Given a source is missing signer identity, When displayed in the provenance panel, Then the signer identity field is shown as "Unknown" and no provenance attribute is omitted. Given two sources disagree on the fact value, When the fact card is viewed, Then both sources' provenance rows are shown side-by-side and clearly associated with their respective values.
API Provenance Payload for Fact
Given a firm API token, When the client retrieves a fact via the CaseSpark API, Then the response includes a provenance array where each element contains: inputChannel (string), documentType (string), signerIdentity (string|null), verificationState (one of Verified|Unverified|Unknown|Failed), uploadHash (64-char hex SHA-256), timestamp (ISO 8601 UTC string). Given a fact with two documented sources, When the API response is parsed, Then provenance.length equals 2 and all required keys and types are present on each element. Given the original uploaded file is available, When its SHA-256 is computed externally, Then it matches the uploadHash returned in the API for that source.
Trust Score Calculation and Confidence Influence
Given trust weights configured as notarizedDocument=0.70 and webIntake=0.30 and two sources disagree on a fact, When the system recomputes the proposal, Then the value supported by the notarized document displays confidence 0.70 (±0.01 due to rounding) and the value supported by the web intake displays confidence 0.30 (±0.01). Given trust weights are updated (e.g., webIntake from 0.30 to 0.50) and settings are saved, When the fact is re-evaluated, Then the displayed confidence values in the UI and API update within 1 second to reflect the new weights. Given a proposal is shown, When the confidence is displayed, Then confidence notes include at least "document support" and, when applicable by timestamps, "date proximity".
Firm-Level Trust Weight Tuning and Policy Threshold
Given a firm admin opens CaseSpark Settings > Fact Harmonizer > Trust & Policies, When they edit trust weights per input channel, document type, and verification state, Then values are constrained to 0.00–1.00 with two-decimal precision and cannot be saved if out of range. Given a Minimum Proposal Confidence policy of 0.80 is set and saved, When a proposed value evaluates to 0.79, Then the item is labeled "Needs Review" and one-tap accept is not preselected; When it evaluates to 0.80 or higher, Then it is labeled "Ready to Accept" and one-tap accept is enabled. Given changes are saved, When a new reconciliation is triggered (refresh or new intake), Then the new weights and policies are applied to the computation immediately (within 5 seconds).
Document Verification Service Integration
Given a document verification provider is configured with a valid API key, When a user uploads a notarized PDF supporting a fact, Then the system calls the provider and sets verificationState to Verified on success, Unverified if explicitly returned as not verified, and Unknown if the provider times out or returns an error. Given verificationState is set from the provider's response, When trust scoring runs, Then the configured weight for that verification state is used in the confidence computation. Given the provider returns within SLA, When the upload completes, Then the verification result is reflected in the UI provenance and API within 10 seconds.
Upload Hash and Timestamp Integrity
Given a PDF is uploaded as a source, When the system stores provenance, Then uploadHash is computed as the SHA-256 of the file and timestamp is recorded in UTC with millisecond precision in ISO 8601 format. Given the exact same file is re-uploaded, When provenance is inspected, Then uploadHash matches the prior value; Given a modified file, Then uploadHash differs. Given a user in a non-UTC timezone views the provenance, When the timestamp is displayed in the UI, Then it appears converted to the user's local timezone while the API continues to return UTC.
Jurisdiction-Aware Fact Rules
"As a family-law attorney, I want contradictions and suggestions to respect my jurisdiction’s rules so that reconciled facts are filing-ready."
Description

Applies state and county-specific family-law validations and heuristics (e.g., residency duration requirements, child age vs. school grade consistency, support guideline thresholds, date window checks) to enhance contradiction detection and proposal confidence. Maintains a versioned rule library, supports overrides with required justification, and localizes messages to align with CaseSpark’s jurisdiction engine.

Acceptance Criteria
Residency Duration Validation by State/County
- Given jurisdiction = CA/Alameda and filing date = 2025-01-15, When petitioner address history shows move-in on 2024-09-20 (117 days), Then Fact Harmonizer flags a contradiction in Residency Duration with severity=Blocker, displays side-by-side claimed duration vs computed 117 days, proposes reconciled value "Residency duration: 117 days (below 180-day requirement)", and adds confidence notes citing date proximity and lack of supporting lease document. - Given jurisdiction = CA/Alameda and computed residency >= 180 days for the filing date, When checks run, Then no contradiction is raised for Residency Duration, a confirmation note states "meets ≥180 days per rule CA-AL-RES vX.Y", and confidence >= 0.9 is recorded. - Given the filing date changes by the user, When checks re-run, Then residency duration is re-computed and the contradiction/proposal updates within 300 ms per party fact set and the audit log records the applied rule id and version. - Given a county override exists (e.g., CA/SF with 90-day local rule) effective for the filing date, When checks run, Then the county-specific threshold is used and the audit log records resolution order county→state→default.
Child Age vs. School Grade Consistency Check
- Given jurisdiction = TX/Travis with kindergarten cutoff = Sep 1 and child DOB = 2018-10-05 (age 6y 11m on filing 2025-09-01) and reported grade = 2nd, When checks run, Then a contradiction is raised in Child Age vs Grade, side-by-side shows DOB/age vs reported grade, proposed reconciled value = "Grade likely 1st" with confidence=0.7, and confidence notes cite age-grade heuristic and cutoff rule. - Given supporting document "Report Card" dated within 60 days confirming grade = 2nd, When checks run, Then proposal changes to "Keep reported grade" with confidence ≥ 0.9 and notes cite document support; the contradiction severity downgrades to Warning. - Given county uses different cutoff, When jurisdiction engine resolves county-specific cutoff and effective window, Then the correct cutoff is applied and referenced by rule id/version in the audit log. - Given a mediator taps Accept on the proposed reconciled grade, When accepted, Then the child fact is updated, the contradiction is resolved, and the resolution is recorded with actor, timestamp, rule id, and confidence at decision time.
Support Guideline Threshold Application
- Given jurisdiction = NY/Kings and rule library defines support guideline threshold T for version V effective on filing date, When combined parental income I is entered, Then Fact Harmonizer evaluates I relative to T, and adds a confidence note: "I < T: guideline method applies" or "I > T: cap/adjustment applies" with rule id/version. - Given reported incomes contradict attached paystubs by >10%, When checks run, Then a contradiction is raised in Income Inputs, side-by-side shows reported vs. computed from documents, and a reconciled income value is proposed with confidence proportional to document recency and coverage. - Given the user accepts the proposed income value, When recomputing threshold condition, Then the support threshold note updates immediately and the contradiction resolves. - Given county-specific deviations exist and are effective for the filing date, When checks run, Then county deviation rules are used and the audit trail shows precedence: county→state→default.
Rule Version Selection by Filing Date Window
- Given two versions of the Residency Duration rule (v1 effective until 2024-12-31, v2 effective from 2025-01-01), When filing date = 2024-12-30, Then v1 is applied; When filing date = 2025-01-02, Then v2 is applied. - Given timezone = jurisdiction-local, When filing date is near midnight UTC, Then the effective window evaluation uses jurisdiction timezone and selects the correct rule version. - Given a rule version is deprecated but still within its end date, When checks run, Then the latest non-deprecated version in-window is selected. - Given rules conflict (multiple candidates in-window), When checks run, Then precedence order county→state→default resolves selection deterministically and the audit log records all candidates and the winner.
Rule Override with Justification and Audit Trail
- Given a contradiction raised by a jurisdiction rule, When a user with role = Attorney attempts override, Then the UI requires a justification (≥ 15 characters), a reason code selection, and optionally a supporting document before enabling Confirm. - Given the override is confirmed, When applied, Then the system records old value, new value, rule id, rule version, jurisdiction, actor, timestamp, justification text, and reason code; the contradiction is marked Overridden and excluded from future duplicate alerts unless facts change. - Given a user without override permission (e.g., Intake Staff), When attempting to override, Then the action is denied and logged, and the contradiction remains open. - Given overridden facts later change (e.g., new document uploaded), When checks run, Then the system prompts to re-evaluate the override and requires re-confirmation if the proposal materially differs.
Jurisdiction-Aligned Localization of Messages
- Given locale = en-US and jurisdiction = LA/Orleans, When a residency rule message is displayed, Then the message uses Louisiana-specific terminology (e.g., parish) via the CaseSpark jurisdiction engine key and renders without missing-token errors. - Given locale = es-US, When contradictions and proposals are shown, Then all rule-generated messages are localized using provided translations with identical placeholders resolved (jurisdiction, thresholds, dates), and fallback to en-US only if a key is missing, with a logged warning. - Given message templates are updated for a rule version, When checks run, Then the message version aligns with the applied rule version in the audit log, ensuring message-content/version parity. - Given side-by-side differences are shown, When messages render, Then each side value has a localized label and units appropriate to jurisdiction (e.g., MM/DD/YYYY vs DD/MM/YYYY date format per locale).
Fallback Behavior for Unknown or Unsupported Jurisdiction
- Given jurisdiction engine cannot resolve county but resolves state, When checks run, Then state-level rules apply and confidence for proposals is reduced by 0.2 with a note "county unresolved—using state defaults". - Given jurisdiction cannot be resolved at all, When checks run, Then generic default heuristics are used, contradictions are flagged with severity=Info, and the UI prompts the user to select a jurisdiction before filing can proceed. - Given jurisdiction becomes known after initial intake, When re-running checks, Then all previously default-based contradictions/proposals are re-evaluated under the resolved jurisdiction and updated within 300 ms per fact group, with prior results retained in the audit trail for comparison. - Given a county is unsupported in the rule library, When checks run, Then the system explicitly logs "unsupported county" and falls back to state rule version with clear localization of the message and a link to request rule addition.
Sync to Document Assembly & Case Record
"As an attorney, I want resolved facts to automatically update my document drafts and case record so that I don’t have to re-enter data and risk errors."
Description

Writes reconciled facts to the canonical case store and immediately updates mapped fields in document templates and checklists. Triggers selective re-generation of affected documents, re-runs conflict screening when sensitive facts change, and preserves a change log with before/after values and approver. Provides exportable summaries for filing packets and integrates with CaseSpark’s tasking and notification systems.

Acceptance Criteria
Immediate Propagation to Case Store and Templates
Given a reconciled fact is approved in Fact Harmonizer for an active case When the commit action is executed Then the canonical case store updates the corresponding field value within 5 seconds And all mapped fields in active document templates and checklists reflect the new value within 5 seconds of the case store update And no unmapped fields or unrelated templates/checklists change And the API/UI response includes a success code and the updated case record version number
Selective Document Re-Generation of Impacted Files
Given at least one document template has fields mapped to the changed fact When the reconciled fact is committed Then only documents whose mapped fields changed are queued for re-generation And non-impacted documents retain their current versions unchanged And regenerated documents complete within 30 seconds for up to 10 documents And each regenerated document is versioned with an incremented version number and change note referencing the fact and correlation id And the system displays per-document re-generation status (Queued, In Progress, Done, Failed)
Automatic Conflict Re-Screening on Sensitive Fact Changes
Given the changed fact is in the configured sensitive-fields list When the reconciled fact is committed Then conflict screening is re-run automatically within 3 seconds using the updated values And the screening result, timestamp, and ruleset version are stored on the case And if the result is Potential Conflict with severity >= Medium, document re-generation is suppressed and a Conflict Review task is created And if the result is No Conflict, pending document re-generation proceeds
Immutable Change Log with Before/After and Approver
Given a reconciled fact is committed When the case store write succeeds Then a change log entry records the field identifier, before value, after value, approver, approver role, timestamp (UTC), and correlation id, with optional reason/note And the entry is immutable and tamper-evident (hash chained) And the change log is filterable by field, date range, approver, and correlation id via UI and API And the change log can be exported to CSV and JSON including all recorded attributes
Exportable Filing Packet Summary Generation
Given reconciled facts exist for the case When the user requests an exportable filing packet summary Then the system generates a PDF and JSON summary within 10 seconds And the summary includes each reconciled fact, its current value, confidence notes, source citations (if any), approver, approval timestamp, and latest conflict-screen result And the export uses the naming convention {CaseId}_FilingSummary_{YYYYMMDDHHmm}_v{n} And the export is downloadable and saved to the case with a unique document id
Tasking and Notification Integration on Sync Events
Given a commit leads to document re-generation and/or a conflict re-screen result When the triggering event occurs Then tasks are created and assigned to the correct role (e.g., Clerk for regen failures, Attorney for conflict review) with due dates per SLA configuration And notifications are sent to case watchers and the triggering user within 5 seconds via in-app and email channels And duplicate tasks/notifications are deduplicated by correlation id within a 30-minute window And each task/notification includes deep links to the case, the change log entry, and affected documents

DualVault

Provide two private upload portals that feed a single, mediator‑visible evidence set. Smart redaction hides sensitive PII across parties while preserving what’s needed for joint filings, so paystubs, orders, and IDs can be collected fast without oversharing.

Requirements

Dual Party Upload Portals
"As a family-law client, I want a private, simple link to securely upload my documents so that I can submit what’s needed without the other party seeing my portal or personal files."
Description

Provide two isolated, role-specific upload portals per matter (e.g., Party A/Party B) with unique expiring invite links, email/SMS OTP verification, and mobile-first drag-and-drop/file picker support. Each portal captures document type, party, and matter metadata; shows upload progress; and supports large-file chunking and resumable uploads. Submissions are automatically associated to the CaseSpark matter, trigger the redaction pipeline, and feed a shared evidence set. Includes branded instructions, checklist guidance, and automated reminders to accelerate document collection while ensuring neither party can access the other’s private portal.

Acceptance Criteria
Secure Access via Expiring Invite Links and OTP
- Given a matter with Party A and Party B, when an invite is generated for each party, then a unique, single-use link is created per party that expires according to the configured TTL. - Given a recipient opens their invite link before expiry, when they request a one-time passcode (OTP) by email or SMS, then access is granted only after entering the correct OTP within its validity window. - Given an incorrect, expired, or reused OTP, when the user attempts to verify, then access is denied and no portal content is revealed. - Given an expired or revoked invite link, when it is visited, then the portal shows an expiration message and provides a secure path to request a new invite without revealing party details. - Given a Party A invite link, when it is used, then it can only access Party A’s portal and cannot be used to access Party B’s portal.
Portal Isolation and Cross-Party Access Control
- Given Party A is authenticated in their portal, when they navigate or attempt to list files, then no Party B files, metadata, or filenames are visible or discoverable. - Given Party A attempts to access a Party B asset directly via URL, ID, or API, when the request is made, then the system returns an authorization failure and does not disclose whether the resource exists. - Given Party B uploads a document, when Party A refreshes their portal, then Party B’s uploads do not appear in Party A’s portal. - Given cross-origin or cross-session attempts to reuse tokens, when a request is made, then tokens are scoped to the party and matter and cannot grant access to the other party’s portal.
Mobile-First Upload UX with Drag-and-Drop and File Picker
- Given a mobile device (narrow viewport), when the portal loads, then controls are touch-friendly and the file picker is available; drag-and-drop is enabled where supported by the browser. - Given a user selects multiple files via file picker or drags a batch, when upload is initiated, then all selected files queue successfully without page reload. - Given an unsupported file type is selected, when validation runs, then the file is rejected with a clear message and does not begin uploading. - Given slow connections, when uploads proceed, then the UI remains responsive and indicates ongoing activity without blocking other interactions.
Large-File Chunking, Resumable Uploads, and Progress Indicators
- Given a file larger than the configured chunk size, when the upload starts, then the client uploads in chunks and the server assembles the file upon completion. - Given a network interruption during upload, when connectivity is restored, then the upload resumes from the last confirmed chunk without data loss. - Given one or more files are uploading, when the UI renders progress, then per-file progress and overall queue progress are displayed accurately from 0% to 100%. - Given a partially uploaded file, when the user reopens the portal on the same device/session, then the upload can be resumed without restarting from 0%. - Given an upload fails irrecoverably, when retries are exhausted, then the user is shown a clear failure state with an option to retry from the beginning.
Metadata Capture and Matter Association
- Given a user is in a party portal, when they add a file to the queue, then the party and matter are auto-associated and immutable by the user. - Given firm-configured document types are available, when a user selects a document type before or during upload, then the selection is stored with the file as metadata. - Given an upload completes, when the record is saved, then the file, party, matter, document type, timestamp, and uploader contact are persisted and visible to staff in the matter. - Given metadata is missing or invalid, when the user attempts to submit, then validation prevents submission and explains what must be corrected.
Automatic Redaction Pipeline and Shared Evidence Feed
- Given an upload completes successfully, when post-processing begins, then the redaction pipeline is triggered automatically for that file. - Given configured PII patterns and rules, when redaction runs, then matching PII is masked in the mediator-visible version while preserving content required for joint filings. - Given redaction completes, when the shared evidence set is refreshed, then the redacted derivative appears in the mediator-visible evidence list, linked to the original. - Given the uploading party views their portal, when they access their own files, then the original (unredacted) versions remain available to that party and staff, not to the other party. - Given redaction fails, when the evidence list updates, then the file is withheld from the shared set and a retry/alert is generated for staff.
Branded Instructions, Checklist Guidance, and Automated Reminders
- Given firm branding and matter-specific instructions are configured, when a party opens the portal, then the header/footer reflect the firm brand and the instructions render above the upload area. - Given a matter checklist defines required document types, when a party views the portal, then a checklist shows required vs. received items with real-time status as uploads complete. - Given required items are incomplete by a configured reminder schedule, when the schedule elapses, then an automated reminder is sent via email/SMS with a secure portal link, and reminders stop once all required items are received. - Given a reminder is delivered, when the recipient follows the link, then they are directed to the correct party portal and must re-verify via OTP if their session is not active.
Smart Cross-Party PII Redaction Engine
"As an attorney-mediator, I want PII automatically redacted according to local rules while preserving data required for filings so that we can exchange evidence quickly without oversharing sensitive information."
Description

Automate detection and removal of sensitive PII (e.g., SSN, DOB, driver’s license, bank/ account numbers, addresses, emails, phone numbers) using pattern rules and OCR-backed text extraction, with configurable, jurisdiction-aware redaction profiles by document type. Maintain three versions per file: original (vaulted), mediator-view (minimal redaction), and counterparty-view (maximal redaction). Preserve fields required for joint filings while masking extraneous PII; provide visual previews, confidence scoring, and inline justification notes. Originals remain encrypted and never shared; redacted derivatives carry watermarks indicating scope and date of redaction.

Acceptance Criteria
OCR-based PII detection on scanned paystub upload (Party A)
Given a 10-page scanned paystub PDF contains SSN, DOB, driver’s license number, bank/account numbers, addresses, emails, and phone numbers And the active redaction profile marks these PII types as sensitive for the counterparty view When Party A uploads the document via their private portal Then the system performs OCR across all pages and layers and detects instances of those PII types And generates redaction boxes for every detected instance And the counterparty-view derivative shows those instances fully masked with no unredacted occurrences remaining And the mediator-view derivative applies only the minimal masks specified by the profile And the original remains unaltered and vaulted
Jurisdiction- and document-type profile selection and enforcement (CA • Paystub)
Given the firm’s redaction profiles include a CA • Paystub profile with explicit keep/mask rules (e.g., SSN last-4 visible to mediator; fully masked to counterparty) And the uploaded document is classified as Paystub and tagged with jurisdiction CA When the engine selects and applies the applicable profile Then the mediator-view derivative preserves exactly the configured fields and formats and masks all others And the counterparty-view derivative applies maximal masking per the same profile And the applied profile ID and version are recorded in the audit log and embedded in derivative metadata
Three-version lifecycle and access control for uploaded evidence
Given a document is uploaded by any party When redaction processing completes Then the system stores three versions: Original (vaulted), Mediator View (minimal), Counterparty View (maximal) And the original is never accessible to mediator or counterparty via UI, download, print, or API And access controls enforce mediator sees only Mediator View and the opposing party sees only Counterparty View And each derivative is watermarked with scope and redaction date
Reviewer preview with confidence scoring and required justification notes
Given a reviewer opens the redaction preview for a processed document And the engine has assigned confidence scores to each detected PII instance When any instance has a confidence score below the configured threshold T Then the UI requires an inline justification note before approval can proceed And each note is saved with user, timestamp, and instance ID And the approval action is blocked until required notes are provided And justification notes are included in the document’s audit trail
Cross-party evidence exposure rules in mediator-visible set
Given Party A and Party B upload evidence into their respective portals When the mediator views the combined evidence set Then the mediator sees Mediator View derivatives for both parties’ documents And Party A, when viewing Party B’s documents, is served only Party B’s Counterparty View derivatives And Party B, when viewing Party A’s documents, is served only Party A’s Counterparty View derivatives And no original files are exposed in any view
Immutable redactions and PII anti-reversal safeguards
Given a redacted derivative (PDF) has been generated When a user attempts to select, copy, search, or extract text from redacted regions Then the masked content cannot be retrieved via selection, copy/paste, search indexing, OCR, or PDF text extraction APIs And redaction overlays are burned-in or rasterized so underlying content is not visible at any zoom level or on print And hidden text layers, form fields, annotations, and file metadata do not contain the masked content
Watermarking, timestamping, and audit trail completeness
Given mediator-view and counterparty-view derivatives are produced When a user opens or downloads a derivative Then a visible watermark displays the scope (Mediator View or Counterparty View) and the redaction date/time And the audit log records document ID, applied profile ID/version, scope, redaction timestamp, reviewer (if any), and a cryptographic hash of each derivative And the audit log contains no entries indicating mediator or counterparty access to the original
Unified Mediator Evidence Set
"As a mediator, I want a consolidated, searchable evidence view with clear redaction status so that I can organize materials and prepare joint filings efficiently."
Description

Merge both parties’ submissions into a single mediator-visible evidence set with deduplication (content hashing), source-party attribution, and document status badges (uploaded, redacted, released). Provide full-text search, filters by party/type/date, annotations, and exhibit labeling. Enable export to indexed PDF/ZIP bundles and direct handoff to CaseSpark’s document assembly to pull only necessary fields into jurisdiction-specific pleadings. Ensure the mediator view reflects the latest approved redaction state and clearly indicates which version is safe for cross-party sharing.

Acceptance Criteria
Content-Hash Deduplication with Source Attribution
Given Party A uploads document D1 and Party B uploads a bit-identical document D2 When ingestion completes Then the system computes a SHA-256 on the original binary of each upload and stores a single evidence record keyed by that hash And the record displays a Deduplicated badge and lists source-party attribution as [Party A, Party B] And duplicate filenames with different hashes are treated as distinct records And repeat uploads by the same party attach as duplicates to the same record with timestamps And each evidence record has a stable Evidence ID
Document Status Badges and Workflow
Given an ingested document passes virus scan and text extraction Then its status badge shows Uploaded When a mediator approves a saved redaction version Vn for that document Then the status badge shows Redacted and the active version is Vn When the mediator marks Vn as share-safe Then the status badge shows Released and cross-party share/export are enabled And sharing/export is blocked for any document not in Released status And status transitions occur only in order Uploaded -> Redacted -> Released and are audit-logged
Mediator View Honors Approved Redaction and Share-Safe Version
Given a document with both original and redacted versions When the mediator opens the Unified Evidence view Then the viewer displays the latest approved redacted version by default with a Share-Safe indicator if Released And the original version is accessible to the mediator with a Private watermark and is never used for cross-party sharing And updating the approved redaction updates the viewer, indicators, and export source within 2 seconds
Full-Text Search Across Unified Evidence
Given a matter with up to 5,000 documents totaling ≤ 2 GB When the mediator searches for a term, an "exact phrase" in quotes, or a prefix with wildcard such as payst* Then results return within 2 seconds for the 95th percentile and highlight hit snippets And search is case-insensitive and includes OCR/text-extracted content And filters, if applied, narrow search results using AND logic
Filters by Party, Type, and Date
Given filters for Party, Type, and Date are available When the mediator selects Party A Then only records attributed to Party A are shown When the mediator selects document types [ID, Paystub, Court Order] Then only records with those types are shown When the mediator sets an inclusive date range on Upload Date and/or Document Date Then results are restricted accordingly and counts update And applying multiple filters intersects results; clearing filters resets the set
Annotations and Exhibit Labeling
Given the mediator is viewing a document When they add a highlight, sticky note, or page note and save Then the annotation is stored without altering the source file, timestamped and attributed to the mediator When the mediator assigns an exhibit label Then it is unique within the matter, auto-increments (Exhibit 1, Exhibit 2, ...), and appears in list, viewer, and exports And changing or removing a label propagates everywhere within 2 seconds And annotations are private to the mediator by default and excluded from cross-party exports unless explicitly included
Export Bundles and Document Assembly Handoff
Given the mediator selects one or more evidence records When exporting as PDF Then a single PDF is generated with a cover index (exhibit label, title, parties, dates, page counts), bookmarks per item, and uses share-safe versions When exporting as ZIP Then the ZIP contains an exhibits/ folder with files prefixed by exhibit labels, an index.csv and index.json with metadata, and a manifest.txt with SHA-256 checksums And export completes within 60 seconds for up to 500 documents or 500 MB When handing off to CaseSpark document assembly with a jurisdiction-specific template Then only mapped fields required by that template are extracted from Released versions and populated, with no unmapped or unreleased PII included And the handoff completes within 10 seconds and returns a success receipt with populated field counts
Role-Based Access Controls & Sharing Rules
"As an attorney, I want to control who can view, download, or release each document so that confidentiality is preserved and we comply with ethical and legal requirements."
Description

Implement granular RBAC across roles (Party A, Party B, Attorney, Staff, Mediator) with default visibility rules: parties see only their own uploads; mediator sees all; counterpart documents are visible only in their approved redacted form. Support link expiration, view-only mode, watermarking, download/print restrictions, and per-document release toggles. Include policy templates per jurisdiction and firm, plus event-based automation (e.g., auto-release paystubs after redaction approval). All access decisions are evaluated server-side and logged for compliance.

Acceptance Criteria
Party Upload Isolation and Redacted Counterparty View
Given Party A and Party B are participants in the same matter and Party B uploads a document into their private portal, When Party A signs in and views the evidence list, Then Party A sees none of Party B’s documents or metadata (filename, size, uploader, tags) until a release occurs. Given a document has an approved redaction and the per-document release toggle is switched ON for counterparty visibility, When Party A refreshes the evidence list, Then Party A sees only the approved redacted version with a visible “Redacted” label and no access path to the original. Given the original unredacted document URL is guessed or requested directly by Party A, When the request is made, Then the server returns 403 Forbidden and logs the denied access decision with reason "not_authorized_original". Given the per-document release toggle is switched OFF or redaction approval is revoked, When Party A attempts to access the previously visible redacted document, Then access is immediately removed and the item is no longer visible in Party A’s list.
Mediator Omni-Visibility Across DualVault
Given a Mediator is assigned to a matter with Party A and Party B using DualVault, When the Mediator signs in and opens the evidence set, Then the Mediator can view all uploaded documents from both parties, including both redacted and original versions, clearly labeled by version and party of origin. Given the Mediator opens any document, When the viewer loads, Then both redacted and original versions (if they exist) are selectable, and the selection action is logged with document version identifiers. Given the Mediator is not assigned to a different matter, When the Mediator attempts to access documents from that other matter via direct URL or list endpoint, Then the server returns 404 Not Found (no existence leakage) and logs the denied decision with reason "scoped_access_violation".
Server-Side Access Evaluation and Immutable Audit Logging
Given any user (Party, Attorney, Staff, Mediator) attempts to list, view, download, print, or share a document, When the request reaches the server, Then the server evaluates RBAC and sharing rules server-side without relying on client state and returns only authorized data. Given an access decision is made (allow or deny), When the response is sent, Then an immutable audit record is appended containing actor ID, role, firm ID, matter ID, document ID, document version, policy template ID and version, decision (allow/deny), reason code, and timestamp. Given an administrator queries audit logs for a matter and time range, When the query executes, Then results include all access decisions for that scope and cannot be edited or deleted via the application UI (read-only retrieval only). Given a user tampers with client code to enable hidden UI actions, When they invoke a restricted endpoint, Then the server still enforces RBAC and returns 403 Forbidden, with a logged reason "client_tamper_blocked".
Expiring Links, View-Only Mode, Watermarking, and Download/Print Restrictions
Given an Attorney creates a share link with an expiration timestamp and view-only mode enabled for a specific document, When a recipient uses the link before expiration, Then the document opens in an inline viewer with persistent page-level watermark including recipient identity (email if authenticated or token ID if anonymous), access timestamp, IP, and matter ID. Given the same share link, When the recipient attempts to download or print, Then the server blocks download and print routes (HTTP 403) and the UI disables those controls; each blocked attempt is logged with reason "view_only_restriction". Given the share link passes its expiration time, When any user attempts to access it, Then the server returns 410 Gone and the audit log records reason "link_expired" with the original expiration timestamp. Given watermarking is enabled by policy, When the document is viewed by any role, Then the watermark appears on every rendered page and includes the viewer’s role and user identifier. Given a share link is revoked manually prior to expiration, When a user attempts to access it thereafter, Then the server returns 410 Gone with reason "link_revoked".
Per-Document Release Toggle with Redaction Gating
Given a document is uploaded by Party B and has not passed redaction approval, When an Attorney attempts to toggle release to Party A, Then the UI prevents enabling release and the server returns 409 Conflict with reason "redaction_not_approved". Given a document has an approved redaction version, When the per-document release toggle is turned ON for the counterparty, Then only the approved redacted version becomes visible to the counterparty and the original remains inaccessible; the action is logged with the redaction version ID. Given the release toggle is turned OFF, When the counterparty refreshes their evidence list, Then the document immediately disappears from their view and any existing share links for that redacted version are invalidated. Given bulk selection of multiple documents with approved redactions, When the Attorney applies “Release to Counterparty”, Then all selected items become visible in redacted form only, and a single bulk audit record references all affected document IDs.
Jurisdiction and Firm Policy Templates with Precedence
Given an Administrator selects a jurisdiction policy template (e.g., CA Family Law) for a matter, When the template is applied, Then default rules (e.g., watermarking=ON, view-only for parties=ON, PII redaction patterns for SSN, DL#, DOB) are set for the matter with a recorded policy version. Given the firm has a firm-level policy template with overrides, When both jurisdiction and firm templates are active, Then the effective policy is resolved with firm overrides taking precedence where allowed, and a computed policy view shows the final values and precedence source for each rule. Given a policy template is updated to a new version, When the matter is opened thereafter, Then the new policy version applies prospectively to new actions while existing audit records reference the prior policy version; policy versions cannot be deleted if referenced by audits. Given a matter is transferred to a different jurisdiction template, When the template is switched, Then the system prompts to review conflicts and applies the new defaults without silently weakening any existing restrictions (e.g., download remain disabled unless explicitly re-enabled).
Event-Based Automation: Auto-Release After Redaction Approval
Given a document is classified as Paystub and has a pending redaction review task, When a Staff user marks the redaction as Approved, Then the system automatically releases the redacted version to the counterparty if the effective policy allows auto-release for that class, and logs an automation event with rule ID. Given the auto-release executes, When the counterparty next views their evidence list, Then the newly released redacted Paystub appears with label “Auto-Released” and the original remains inaccessible. Given policy disables auto-release for a document class or matter, When redaction is approved, Then no release occurs and an audit record notes reason "automation_suppressed_by_policy". Given a previously approved redaction is revoked or a superseding redaction version is submitted, When the event fires, Then the system withdraws counterparty access to the earlier redacted version and replaces it with the newly approved version only after approval, logging both withdrawal and replacement events.
Chain-of-Custody Audit Trail
"As a mediator, I want a complete, exportable chain-of-custody log so that the integrity and provenance of evidence can be defended if challenged."
Description

Record a tamper-evident audit log for each file and derivative, including event type (upload, scan, OCR, redaction, review, release, view, download, export), timestamp, actor, IP/device fingerprint, and SHA-256 content hashes pre/post transformation. Provide exportable audit reports (PDF/JSON) suitable for court submission and integrate entries into the CaseSpark matter timeline. Surface integrity alerts on mismatch or altered derivatives and support time-based retention policies aligned with firm standards.

Acceptance Criteria
End-to-End Audit Logging for Uploads and Transformations
Given a file is uploaded via either DualVault portal, when the upload completes, then an audit entry is appended with fields: eventType=upload; timestamp ISO 8601 with UTC offset; actorId; actorRole; ipAddress; deviceFingerprint; matterId; portalId; fileId; sha256Post computed from stored binary; sha256Pre=null. And when the system performs scan, OCR, redaction, review, or release on the file, then for each operation an audit entry is appended with eventType in {scan, OCR, redaction, review, release} and fields including sha256Pre (hash of input), sha256Post (hash of output), parentFileId for derivatives, and matterId. And when a user performs view, download, or export, then audit entries with eventType in {view, download, export} are appended with sha256Pre set to the served artifact’s hash and sha256Post=null. And audit entries are written successfully before the resulting artifact is made available to any other user or response is returned.
Cryptographic Tamper-Evidence and Verification
Given an audit log exists for a file, when integrity verification runs, then each entry contains a chainHash that links cryptographically to the previous entry and the computed chain validates end-to-end without gaps. And if any entry is modified, deleted, or reordered, then verification fails and an Integrity Alert with severity=high is recorded and surfaced on the matter timeline and file detail. And a daily anchor hash per matter is persisted to immutable storage and verification confirms the chain for the covered period matches the stored anchor.
Integrity Alerts on Hash Mismatch or Altered Derivatives
Given a derivative event (e.g., redaction) is created, when the system computes sha256Pre from the source and sha256Post from the generated derivative, then the entry stores both values and the parent-child linkage. And if sha256Pre does not match the parent artifact’s sha256Post, or if the derivative’s sha256Post changes after creation, then an Integrity Alert is generated within 5 seconds, displayed on the file and matter views, and included in audit exports. And integrity alerts require resolution by a user with role attorney or admin, and the resolution action is itself logged as an audit event.
Court-Ready Audit Report Export (PDF and JSON)
Given a user with permission Export Audit selects Export (PDF or JSON) and a date range, file(s), and matter, when export runs, then the system produces a report containing all audit entries and fields (eventType, timestamp, actorId, actorRole, ipAddress, deviceFingerprint, sha256Pre, sha256Post, fileId, parentFileId, matterId) and a verification summary (pass/fail, lastVerifiedAt, anchorHash). And the PDF is digitally signed, includes page numbers, UTC timestamps, and a report SHA-256, and the JSON conforms to a published schema with field names and types. And generating the export writes an audit entry with eventType=export including format and filter parameters. And exported filenames include matterId, file scope, date range, and report hash.
Matter Timeline Integration and Access Control
Given a firm user views the CaseSpark matter timeline, when filters (date range, eventType, actor, portal, fileId) are applied, then audit entries are displayed in chronological order with event icons and a link to the associated file or derivative. And users with roles attorney and paralegal can view full audit details; users without permission cannot see ipAddress or deviceFingerprint values; denied access attempts are blocked and logged. And expanding an entry reveals sha256Pre, sha256Post, and parent-child linkage; activating Verify Integrity runs verification and shows status inline.
Time-Based Retention and Legal Hold Enforcement
Given firm retention settings are configured (e.g., N years after matter close), when the retention date arrives, then the system purges eligible audit data and derivatives per policy, appends a purge audit event, and updates chain anchors so verification passes for the retained scope. And when a legal hold is applied to a matter, then no purge occurs until the hold is released; both placement and release are logged with actor, timestamp, and reason. And retention settings are versioned and changes (old value, new value, effective date, actor) are recorded in the audit log.
Complete Event Type Coverage and Field Capture
Given users and system processes perform actions on a file, when actions of type upload, scan, OCR, redaction, review, release, view, download, export occur, then a corresponding audit entry is created for each action with all required fields populated and non-null except sha256Pre/sha256Post as defined by the event. And event records are rejected and the action is blocked if any required field is missing or if timestamp is not ISO 8601 with timezone; an error is displayed and logged. And audit entries for user-facing actions (view, download, export) are recorded before the client receives the response.
File Validation, Security Scanning, and OCR Normalization
"As a client, I want the system to accept my photos and scans and make them searchable so that I can submit evidence without special software or extra steps."
Description

Validate and normalize incoming files (PDF, DOCX, XLSX, JPG/PNG/HEIC, EML) with server-side antivirus scanning, file-type and size checks, and encrypted-at-rest storage. Auto-OCR images and scanned PDFs to enable search and redaction; normalize PDFs (flatten, rotate, deskew, merge/split) while preserving originals. Detect encrypted or corrupted files, provide client-friendly error messages and retry support, and quarantine unsafe uploads. Extract structured text and metadata to improve redaction accuracy and document assembly downstream.

Acceptance Criteria
Antivirus Scanning and Quarantine
Given a user uploads a supported file via Portal A or Portal B When the server-side antivirus scan flags malware or a suspicious signature Then the file is moved to a quarantine location, is not indexed, and is inaccessible to all roles including mediator Given a file is quarantined When the upload session concludes Then the uploader sees a single client-friendly error message with a retry option and a generic reason (e.g., "unsafe file detected") Given a file is quarantined When viewed in the staff audit log by an Intake Admin Then the log shows timestamp, uploader internal ID, portal (A/B), SHA-256, reason=MalwareDetected, quarantineId, and no file content preview Given a file passes antivirus scan When scanning completes Then the next stage (validation) begins within 1 second of scan completion
File Type and Size Validation with Client Messaging and Retry
Given a user uploads a file When the file type is not one of PDF, DOCX, XLSX, JPG, JPEG, PNG, HEIC, or EML Then the upload is rejected before storage and the user sees a message listing allowed types and a retry option Given a user uploads a file When the file size exceeds 100 MB or the session total exceeds 1 GB Then the upload is rejected and the user sees the enforced limits and retry guidance Given a user uploads a valid file type within limits When validation passes Then the file is accepted and the user sees a success state within 1 second Given a user upload fails validation When the user retries with a valid file Then the retry succeeds without requiring page refresh and the first failure is recorded in the audit log with reason
Auto-OCR for Images and Scanned PDFs
Given an image (JPG, PNG, HEIC) or a scanned PDF lacking a text layer When the file is accepted Then OCR is performed automatically and a searchable text layer is added to the derivative Given a 50-page 300 DPI scanned PDF (≤25 MB) When OCR starts Then OCR completes within 120 seconds at the 95th percentile and exposes page-level text via API and search Given OCR completes When a user searches for a term present in the document Then the viewer highlights at least one matching occurrence with correct page reference Given OCR fails When retry logic is invoked Then the system retries up to 2 times with exponential backoff and surfaces a non-blocking warning to staff while preserving the original
PDF Normalization While Preserving Originals
Given an uploaded PDF with form fields, rotation issues, or skew When normalization runs Then the derivative PDF is flattened, rotated to upright text orientation, and deskewed up to 5 degrees Given multiple PDFs uploaded in the same session When merge is requested by workflow rules Then a single normalized derivative is created in the specified order and page count matches the sum of inputs Given a normalized derivative is created When a staff user with proper role requests the original Then the exact original file remains retrievable via a distinct "Original" artifact ID and hash matches the upload hash Given normalization runs When an error occurs on any page Then the job reports which page failed, creates a partial derivative excluding failed pages, and retains originals
Detection of Encrypted or Corrupted Files with Guided Retry
Given a user uploads a password-protected PDF or Office file When validation inspects the file Then the system detects encryption, rejects processing, and prompts the user to remove the password and re-upload with a retry option Given a user uploads a corrupted or unreadable file When parsing fails Then the system rejects the file, preserves no partial content, and displays a friendly error with tips to re-export or photograph and re-upload Given an encrypted or corrupted file is rejected When staff review the audit log Then the log includes file hash, portal (A/B), reason (EncryptedFile or CorruptedFile), and no content Given a user re-uploads a valid replacement within the same session When validation passes Then the new file replaces the failed attempt in the intake package while keeping an audit trail link
Structured Text and Metadata Extraction for Redaction and Assembly
Given a supported file is accepted When processing completes Then structured text and metadata (page count, per-page text, detected language, document properties, and for EML: From, To, Subject, Date, attachments list) are stored in a secure index Given text is extracted When PII patterns (e.g., SSN, DOB, bank account) are detected Then only tags and page coordinates are stored; raw PII is not exposed across portals and is accessible only to staff with Redaction permissions Given an EML with attachments is processed When extraction runs Then attachments are enumerated, scanned, validated, and linked to the parent email with stable IDs Given structured metadata exists When downstream redaction runs Then hit-highlighting uses extracted coordinates with ≥95% alignment accuracy on a 10-document test set
Encrypted-at-Rest Storage and Controlled Access
Given any file or derivative is stored When inspected in storage Then server-side encryption with AES-256 (SSE-KMS) is enforced and the object metadata indicates the KMS key ID Given a user or staff requests a download link When the system generates access Then a pre-signed URL is issued that expires in 10 minutes, is single-use, and is scoped to the minimal artifact required Given any artifact is accessed or attempted When logging runs Then an immutable audit log records user ID, role, portal (A/B), artifact ID, action, IP, timestamp, and outcome Given a key rotation event occurs When new files are stored Then they use the rotated KMS key; existing objects remain readable and a backfill job is scheduled to re-encrypt within 24 hours
Redaction QA and Exceptions Workflow
"As a paralegal, I want to review and adjust detected redactions and approve exceptions so that only appropriate information is shared with the other party."
Description

Provide a reviewer workflow for validating auto-redactions: side-by-side original/redacted previews, manual redact/unredact tools, batch actions, and confidence-based review queues. Support exception requests (e.g., allow last four digits) with justification, approver roles, and auditable decisions. Generate a disclosure log summarizing what was withheld or revealed and why. On approval, automatically release the appropriate derivative to the counterpart and update the mediator evidence set, with notifications to relevant participants.

Acceptance Criteria
Side-by-Side Preview Validation
Given a reviewer opens a document flagged for redaction review When the preview loads Then the original and redacted versions render side-by-side with synchronized page navigation and scrolling And text search, zoom, and page thumbnails operate on both panes in sync And redaction boxes in the redacted pane display reason codes on hover or click And no redacted content is readable in the redacted pane at up to 400% zoom
Manual Redact/Unredact Tools Functionality
Given a reviewer selects a redact or unredact tool (box, text, pattern) When the reviewer applies a change on a page and saves Then the change applies only to the redacted derivative and the original remains unaltered And the reviewer must select a reason code from a controlled list before saving And undo and redo are available for the last 20 actions And the system records coordinates, page, user, and timestamp for each change
Batch Actions and Bulk Approvals
Given a reviewer selects multiple documents in a review queue When they apply a batch approve, reject, or redaction pattern Then a preflight summary shows document count, pages affected, and estimated processing time And actions execute atomically per document with per-file rollback on failure And a batch of up to 200 documents completes with average processing latency of 2 seconds or less per document And a post-action report lists successes, failures, and retry options
Confidence-Based Review Queues Routing
Given auto-redaction produces findings with confidence scores When queue rules run with a configurable threshold (default 0.92) Then findings below the threshold route to Needs Review And findings at or above the threshold are auto-applied and routed to Auto-Approved And a 5% random sample of auto-approved items appears in a Spot Check queue And users can filter queues by matter, document type, date, and confidence range
Exceptions Request and Approval Workflow
Given a reviewer submits an exception request to reveal limited PII (e.g., last 4 digits of SSN) When the request includes justification, defined scope (document/page/coordinates or pattern), and optional expiration Then only users with the Approver role can approve or deny the request And approval reveals only the specified scope while preserving other redactions And the decision logs approver, timestamp, reason, and links to affected redactions And denial leaves the derivative unchanged and notifies the requester with the reason
Disclosure Log Generation and Integrity
Given a document package is finalized for release When the disclosure log is generated Then the log lists per document the withheld elements, revealed exceptions, page numbers, coordinates (if applicable), reason codes, and decision references And the log is exportable as PDF and CSV with a content hash and immutable audit ID And the log is accessible to the mediator and case owners and is retained for at least 7 years
Release and Notifications to Counterpart and Mediator
Given an approved document package When it is released Then the correct derivative for each audience is delivered (party-redacted to counterpart; mediator-visible set updated) And all relevant participants (requester, reviewer, approver, mediator) receive in-app and email notifications with links and audit IDs And the counterpart cannot access the original unredacted document And prior releases are versioned, with current version labels visible to all viewers

Neutral Nudges

Automated, empathetic reminders and clarifying prompts keep both sides progressing without inflaming tensions. Multilingual, time‑window aware, and tone‑tuned messages request missing details or approvals, boosting completion rates and reducing coordinator follow‑ups.

Requirements

Event-Driven Nudge Orchestration
"As an intake coordinator, I want nudges to auto-trigger from workflow events so that matters keep moving without me chasing each step manually."
Description

Implements a rules-based engine that triggers, schedules, and sequences neutral, empathetic reminders based on workflow events across CaseSpark (e.g., incomplete intake fields, pending conflict check confirmations, missing jurisdictional details, unsigned e-sign packets, stalled document assembly steps). Supports time-window awareness (recipient local timezone, quiet hours, court-day calendars), throttling, deduplication, escalation ladders, and cancellation when tasks are completed. Integrates with CaseSpark’s intake, conflict screening, and document assembly modules via webhooks and internal events, generating context-rich messages with deep links to the exact action needed. Ensures idempotent operations, retry logic, and auditability for every nudge lifecycle state (queued, sent, completed, canceled). Expected outcome: higher completion rates with fewer manual follow-ups and faster progression from call to filing.

Acceptance Criteria
Incomplete Intake Field Triggers Targeted Nudge
Given an active intake with at least one required field missing and no pending nudge for that field in the last 24 hours And the intake service emits event intake.field.missing with event_id, tenant_id, party_id, matter_id, and field_key When the engine processes the event Then it creates a nudge job within 5 seconds tagged with tenant_id, party_id, matter_id, and field_key And selects the neutral-tone template and channel per tenant defaults And selects message language from party preference with fallback to tenant default And includes the localized field display name and a signed deep link that lands on the exact field and expires after 72 hours And the operation is idempotent: reprocessing the same event_id does not create additional jobs And an audit record is written with state=queued and correlation_id=event_id
Quiet Hours and Timezone-Aware Scheduling
Given the recipient timezone is America/Denver and tenant quiet hours are 20:00–08:00 local time And the court-day calendar marks Saturday and Sunday as non-court days and Monday as a court day And a nudge with tag=filing_deadline is generated at 21:15 on Friday local time When the engine schedules the nudge Then send_at is set to 08:05 on Monday (next court day, local time) And no send operation occurs before send_at And the audit log records schedule_reason=quiet_hours and court_day_adjustment=true
Throttling and Deduplication Under Rapid Event Bursts
Given throttle policy is 1 nudge per party per subject_key per 24 hours across all channels And 25 identical events conflict.confirmation.pending with unique event_ids but the same subject_key arrive within 60 seconds for the same party and matter When the engine processes the events Then exactly 1 nudge job exists in queued or scheduled state for that subject_key And the remaining 24 events are recorded as deduplicated with reason=throttled_or_duplicate And metrics report dedup_count=24 for the window And the audit shows a throttling entry referencing all suppressed event_ids
Escalation Ladder for Unresponsive Recipient
Given an intake_missing_details nudge with an escalation ladder: SMS at T0, Email at T0+24h if no completion or link click, Voice at T0+48h if still incomplete And the party has all three reachable channels with delivery-ready statuses When the SMS is sent at T0 and no completion or link click is recorded by T0+24h Then an Email is scheduled and sent at T0+24h±5 minutes And if by T0+48h there is still no completion, a Voice call task is queued And if at any point a completion event or link click is recorded, all pending escalation steps are canceled within 5 seconds And the audit shows each step with state transitions and cancel reasons as applicable
Automatic Cancellation Upon Task Completion
Given a scheduled nudge for subject_key=unsigned_esign with send_at in the future And before send_at the system receives esign.completed via webhook or internal event with matching party_id and matter_id When the engine correlates the completion event Then it cancels the pending nudge within 5 seconds with reason=task_completed And no send attempt is made after cancellation And the audit trail records state=canceled and correlation to the completion event
Idempotent Delivery with Retry on Transient Failures
Given a nudge send attempt to the provider returns a transient error (HTTP 429 or 5xx) When the engine retries with exponential backoff using a stable provider idempotency key for the message Then it retries up to 5 times over 30 minutes or until a success response is received And upon success exactly one outbound message exists at the provider (verified by idempotency key) And upon final failure the nudge is marked state=failed with final_error_code and no further retries are scheduled And all attempts are logged in the audit with attempt_number and outcome
Complete Lifecycle Audit and Exportability
Given any nudge instance from creation through termination When an administrator requests the audit by correlation_id via the API Then the response contains an immutable, chronological list of lifecycle entries including states: queued, scheduled, sent (with provider_message_id), completed (or canceled/failed), and any dedup/throttle decisions And each entry includes timestamp (ms precision), actor/system, reason_code, channel, template_id, and correlation references And the audit is retained per tenant policy with a minimum of 2 years and is exportable as JSON and CSV
Compliance & Ethical Guardrails
"As a managing attorney, I want strict guardrails on who we nudge and what we send so that our communications are ethical, compliant, and safe for sensitive family-law matters."
Description

Enforces legal-ethics and communications compliance before any nudge is sent. Validates consent and preferred channels per contact, checks representation status to avoid messaging represented opposing parties, respects conflict-screening outcomes, and enforces do-not-contact and safety flags (e.g., protective orders, sensitive family situations). Applies TCPA/CAN-SPAM requirements, opt-in/opt-out handling, and jurisdiction-specific disclaimer insertion. Requires identity verification (e.g., OTP) before delivering links containing personal or case data. Provides immutable audit logs of policy checks, content versions, approvals, and delivery outcomes for defensibility. Integrates with CaseSpark contact profiles, matter permissions, and role-based access controls to ensure only appropriate, non-inflammatory, neutral content is delivered.

Acceptance Criteria
Consent and Channel Validation Before Nudge Send
Given a contact exists with recorded consent preferences and preferred channels When a nudge is queued for delivery Then the system must verify explicit opt-in exists for the selected channel with timestamp and source captured And the system must respect the contact’s preferred channel order when multiple consents exist And if no valid opt-in exists for the chosen channel, the send is blocked and a machine-readable reason code is recorded And if the channel is marked prohibited or expired, the send is blocked and the user sees a non-send banner And the consent snapshot (status, channel, timestamp, source) is attached to the nudge event for audit
Representation and Opposing-Party Safeguard
Given a nudge is prepared to a party linked to a matter When the party is marked as an opposing party represented by counsel in the matter Then the system blocks the nudge send for all channels And surfaces a blocking alert citing representation status and firm policy link And records the blocked attempt with user, timestamp, matter, and reason code And allows send only if the recipient is the firm’s own client on the matter and channel consents pass
Conflict and Safety Flag Enforcement
Given contact and matter records carry conflict-screening outcomes and safety/do-not-contact flags When a nudge is queued to the contact Then if conflict outcome is Potential or Confirmed, the send is blocked and escalation workflow is offered And if a do-not-contact or protective-order flag is present, the send is blocked across all channels And if a safe-contact window is defined, delivery is scheduled only within the window based on recipient timezone; otherwise it is blocked with reason And all blocks or schedules include machine-readable codes and are written to the audit log
TCPA/CAN-SPAM Compliance and Opt-In/Out Handling
Given TCPA/CAN-SPAM policies are configured and the recipient’s timezone is known When sending an SMS nudge Then quiet hours are enforced per jurisdiction; messages during quiet hours are queued for next permissible window And SMS includes required opt-out instructions; inbound STOP/UNSUBSCRIBE is processed within 60 seconds and globally suppresses future SMS to that number When sending an email nudge Then the email includes required physical address, functional unsubscribe, and jurisdictional headers And unsubscribe requests are honored within 10 minutes across the workspace And all compliance checks (quiet hours, disclosures, opt-out state) are recorded with pass/fail outcomes
Jurisdiction-Specific Disclaimer Insertion
Given the matter has a governing jurisdiction and recipient language preference When composing a nudge Then the system inserts the jurisdiction-specific disclaimer and attorney advertising notice in the recipient’s language before send And if a jurisdiction mapping is missing or outdated, the send is blocked until an approved disclaimer is selected And disclaimers are versioned; the exact version ID is bound to the outbound message and audit log And the disclaimer is visible in message previews and final sent content
Identity Verification for Sensitive Links
Given a nudge contains any link classified as personal or case data When the message is delivered Then the recipient must complete OTP verification (min 6 digits, expires in 10 minutes) before link content is revealed And after 5 failed OTP attempts within 15 minutes, the link is locked and the sender is notified And verified device fingerprint and verification timestamp are logged and bound to the message event And if identity verification fails or times out, no protected content is transmitted and a retry path is offered
RBAC, Matter Permissions, and Neutral Content Enforcement
Given the sender is authenticated and acting within a matter context When attempting to send a nudge Then the user must have active Nudge:Send permission for the matter and recipient role; otherwise the send is blocked with reason code And template access is restricted by role; only approved neutral templates are selectable And generated content must pass neutrality checks (toxicity < 0.2, sentiment between -0.3 and 0.3, no insults or threats detected); failures block send and surface edit suggestions And all permission checks and neutrality scores are recorded in the immutable audit log
Tone-Tuned Template Library
"As a family-law attorney, I want selectable, tone-tuned templates that keep messages neutral and clear so that clients respond without inflaming tensions."
Description

Delivers a curated library of message templates optimized for family-law contexts with selectable tone profiles (neutral, empathetic, firm-but-polite) that minimize conflict while clearly requesting missing information or approvals. Templates support dynamic variables (names, due dates, jurisdictional fields), conditional text (based on case stage and representation), and microcopy that avoids inflammatory language. Includes approval workflows for template creation/editing, version control, and localization hooks. Integrates with the orchestration engine to assemble the right template at send time and with e-sign/document assembly to embed secure deep links. Expected outcome: consistent, on-brand, de-escalating communication that improves response rates.

Acceptance Criteria
Tone Profile Selection and De‑escalation Enforcement
Given a coordinator selects tone profile "Empathetic" for the "Missing Information" event When the template is previewed or sent Then the rendered subject and body contain 0 terms from the prohibited_terms list And the tone analysis scores Empathetic >= 0.80 and Aggressive <= 0.10 And the reading grade level is <= 8 (Flesch–Kincaid or equivalent) And no word appears in ALL CAPS except approved acronyms And the preview clearly displays the applied tone profile tag
Dynamic Variables Rendering and Validation
Given a template includes variables {client_first_name}, {due_date}, {jurisdiction_court_name}, {case_number}, {secure_link} When orchestration renders the template and any required variable is missing Then the system blocks sending and lists the exact missing variables And no placeholder strings are present in the output When all variables are present Then dates are formatted per locale (e.g., en-US: Sep 10, 2025) And all variables are HTML/URL escaped to prevent injection And personal names are title-cased according to locale rules And the preview highlights substituted values
Conditional Text by Case Stage and Representation
Given a template defines conditional blocks for case_stage in {Intake, ConflictScreening, Filing} and party_representation in {SelfRepresented, Represented} When case_stage = ConflictScreening Then the conflict-screening block is included and non-applicable stage blocks are omitted When case_stage != ConflictScreening Then the conflict-screening block is omitted When party_representation = Represented Then the salutation and microcopy address the attorney of record and exclude direct-to-party language When recipient_role = OpposingParty Then only tone profiles {Neutral, Firm-but-Polite} are selectable and Empathetic is disallowed
Localization and Multilingual Fallbacks
Given a recipient preferred locale of es-MX and an approved es-MX template exists When orchestration requests the template Then the es-MX version is returned and rendered When a locale-specific version is missing Then the system falls back to the base language (e.g., es) else to en-US and logs a fallback event And all variable formats (dates, numbers) follow the selected locale And all rendered characters preserve accents/diacritics without mojibake And the stored message record includes the locale code used
Template Approval Workflow and Version Control
Given a user with role Author creates or edits a template When the template is submitted for approval Then only a user with role Approver can change its status to Approved And only Approved templates are available for orchestration selection When an Approved template is edited Then a new Draft version is created without altering the live Approved version And version history shows version number, author, approver, timestamps, and change summary And an Approved version can be rolled back to a prior Approved version without data loss And attempts to delete an Approved version are blocked; it can only be set to Retired
Contextual Template Selection via Orchestration
Given a case context including {event = RequestMissingIncomeDocs, tone = Neutral, language = en-US, jurisdiction = CA, party_role = Client, case_stage = Intake} When orchestration requests a template Then the library returns the best-matching Approved template within 200 ms at p95 with its variable schema And if multiple candidates match, the most recent Approved version is selected deterministically And if no candidate matches, a TemplateNotFound response is returned with up to 3 nearest alternatives and no send occurs And the selection rationale (filters, fallback decisions) is logged for audit
Secure Deep Links for E‑Sign and Document Assembly
Given a template includes {secure_link} for an e-sign packet or document assembly task When the template is rendered for recipient alice@example.com Then a single-use, HTTPS deep link is generated with a configurable TTL (default 72h) And the link is scoped to the recipient identifier (email/phone) and case ID And the link becomes invalid after successful completion, explicit revocation, or TTL expiry And access attempts are logged with timestamp, IP, user-agent, and outcome And previews mask the token value while preserving the link structure
Multilingual Localization
"As a Spanish-speaking client, I want reminders in my language so that I can understand what’s needed and complete my tasks confidently."
Description

Enables end-to-end multilingual messaging with automatic language selection based on user preferences, intake data, or device locale, with override controls. Provides professionally localized templates for priority languages (e.g., English, Spanish) and supports expansion, including right-to-left scripts. Handles locale-specific formatting (dates, numbers, honorifics) and inserts jurisdiction-appropriate disclaimers per language. Includes translation memory and QA workflows to maintain accuracy and neutrality of tone. Fallback logic ensures safe default language when a translation is unavailable, and the UI surfaces language to staff for review. Expected outcome: accessible, culturally-aware nudges that reduce confusion and increase completion among non-English-speaking clients.

Acceptance Criteria
Automatic Language Selection Precedence
Given a contact with profile language 'es' and device locale 'en-US', When a nudge is generated, Then the nudge language is Spanish and the selection source is recorded as 'profile'. Given a contact without a profile language but intake preferred language 'es', When a nudge is generated, Then the nudge language is Spanish and the selection source is recorded as 'intake'. Given a contact with no profile or intake language and device locale 'en-GB', When a nudge is generated, Then the nudge language is English and the selection source is recorded as 'device'. Given conflicting cues (profile 'es', intake 'en'), When a nudge is generated, Then the nudge language follows precedence profile > intake > device. Given a language is selected, When staff view the message record, Then the chosen language and selection source are visible in the UI and audit log.
Recipient and Staff Override Controls
Given a recipient clicks 'Change language' in a nudge and selects 'English', When the next nudge is generated, Then it is sent in English and the override source is recorded as 'recipient'. Given staff with 'Communications:Edit' permission set the conversation language to 'Spanish', When a scheduled nudge sends, Then it is in Spanish and the override is logged with user ID, timestamp, and scope 'conversation'. Given a staff override exists, When staff revert the setting to 'Automatic', Then the next nudge uses automatic selection and the reversion is logged. Given a user without permission attempts to change the conversation language, When the action is submitted, Then the change is blocked and no override is recorded.
English and Spanish Template Parity and Tone
Given the Neutral Nudges template library, When comparing English and Spanish templates, Then 100% of English templates have a corresponding approved Spanish template with identical placeholders and variable mappings. Given a Spanish template, When rendered with representative sample data, Then the message maintains a neutral, empathetic tone per the approved style guide and meets CEFR B1–B2 readability. Given an English master template is updated, When changes are published, Then a linked localization task is created for Spanish and the Spanish template remains 'Pending QA' until approved by a second reviewer. Given a template requires a jurisdiction disclaimer, When localized to Spanish, Then the Spanish template contains the equivalent jurisdiction-appropriate disclaimer in the correct section.
Locale-Specific Formatting and Disclaimers
Given locale 'es-US', When rendering dates and times, Then formats follow 'MM/dd/yyyy' and 12-hour clock with locale-appropriate labels and the case's timezone. Given locale 'es-ES', When rendering numbers and 12345.67 USD, Then the output is '12.345,67 US$' per locale rules. Given the recipient's gender is unknown, When addressing in Spanish, Then a neutral honorific and salutation are used per the style guide. Given a nudge includes required jurisdiction disclaimers, When sent in Spanish, Then the jurisdiction-appropriate Spanish disclaimer is included and its inclusion is recorded in the message metadata.
Right-to-Left (RTL) Rendering Support
Given language 'ar' is enabled, When composing and sending a nudge, Then the message renders RTL correctly in email, SMS, and the web portal, and UI chrome mirrors where applicable. Given an Arabic template with embedded English URLs and case numbers, When rendered, Then numbers and URLs remain LTR and unbroken while surrounding Arabic text remains RTL. Given an Arabic nudge, When viewed on iOS Mail and Gmail web, Then punctuation placement, line breaks, and emoji render correctly without garbling. Given a variable label lacks Arabic translation, When the nudge is generated, Then the system does not insert the English label inside Arabic text and instead applies the configured fallback behavior.
Safe Fallback Language and Staff Visibility
Given target language 'es' and the Spanish template is unavailable, When generating the nudge, Then the system falls back to the organization-configured safe default language (default: English) and records 'fallback: template missing' with template/version identifiers. Given a fallback was used, When staff view the conversation, Then a visible banner shows the language used and the fallback reason, with a one-click action to request localization. Given fallback occurred, When audit logs are queried, Then an entry exists with timestamp, user/system actor, target language, fallback language, and reason code. Given time-window rules apply to the nudge, When fallback is used, Then the scheduled send time respects the original time window.
Translation Memory and QA Workflow
Given a previously approved EN→ES segment exists in translation memory, When the same English segment appears in a new template, Then the Spanish segment is auto-suggested at 100% match and requires reviewer confirmation before approval. Given a fuzzy match of ≥85% exists in translation memory, When localizing, Then the suggestion is offered with differences highlighted and cannot be auto-approved. Given a maintained bilingual glossary, When a localized template is submitted for QA, Then glossary term compliance is validated automatically and violations block approval with specific flags. Given a localized template passes automated checks, When a different reviewer than the translator approves it, Then the status changes to 'Approved' and the version is locked; subsequent edits reopen localization tasks.
Intelligent Channel Routing
"As a client, I want reminders on the channel and at the times that work for me so that I don’t miss important next steps."
Description

Selects the optimal delivery channel (SMS, email, in-app, voice fallback) per recipient based on consent, preferences, deliverability history, and message type. Implements time-of-day and timezone-aware scheduling, rate limits, and channel failover with exponential backoff. Generates secure, single-use deep links to intake forms, e-sign packets, and document upload flows, with link tracking and expiration. Monitors bounces, undeliverable events, and opt-outs, then adapts routing automatically. Integrates with CaseSpark notification services and contact records to consolidate communication history. Expected outcome: higher deliverability and engagement with minimal coordinator intervention.

Acceptance Criteria
Consent-Driven Channel Selection
Given a recipient has explicit consent per channel and ordered preferences, When a nudge is created, Then the system selects the highest-priority channel that is consented and eligible for the message type. Given no consent exists for a channel, When routing is evaluated, Then that channel is excluded from consideration. Given two channels are equally preferred, When routing is evaluated, Then the channel with the higher 30-day deliverability score is selected. Then the selected channel, consent source, and scoring factors are recorded to the audit log with a correlation ID.
Timezone and Quiet-Hours Scheduling
Given quiet hours are 8pm–8am in the recipient’s timezone, When a send is triggered at 10:00pm local, Then it is deferred to 8:00am next allowed window. Given the recipient’s timezone is unknown, When scheduling, Then the system infers timezone from recent activity or area code; if unavailable, defaults to firm timezone and flags the record. Given a DST transition occurs, When a send is scheduled in a skipped hour, Then it is sent at the next valid local time. Then actual send time is within ±60 seconds of scheduled time under nominal load, and the schedule decision is logged.
Rate Limits and Deduplication
Given a per-recipient limit of L nudges per 24-hour rolling window (configurable, default 3), When the Lth message has been sent, Then additional messages are queued or suppressed per policy until the window resets. Given firm-wide throughput limit of F per hour (configurable), When F is reached, Then subsequent sends are back-pressured and rescheduled fairly across matters. Given multiple nudges with identical purpose and payload are queued within 30 minutes, Then only one is sent and the rest are merged with their references closed as duplicates.
Channel Failover with Exponential Backoff
Given a transient failure on the selected channel, When sending fails, Then retries follow exponential backoff (5m, 15m, 60m) up to 3 attempts before attempting the next eligible channel. Given a permanent failure (hard bounce/invalid), When detected, Then the channel is marked invalid for 30 days and routing immediately fails over to the next eligible channel. Given delivery is confirmed on any channel, When other attempts are pending, Then all pending retries and alternate sends are canceled using an idempotency key.
Secure Single-Use Deep Links
Given a message requires action, When generating the link, Then a signed, single-use URL is created bound to the recipient and message scope, with 12-hour expiry (configurable) and a cryptographic signature with at least 256-bit strength. Given the link is accessed and passes validation, When the action is completed, Then the token is consumed and cannot be reused; subsequent requests return HTTP 410 with non-sensitive guidance. Given the link expires or is revoked, When accessed, Then access is denied and a new link can be requested according to policy. Then link events (delivered, opened, clicked, completed) are captured and stored against the contact and matter; p95 link landing page load time is < 2s from supported regions.
Deliverability Monitoring and Opt-Out Compliance
Given bounce or complaint events are received from providers, When an event occurs, Then it is processed within 2 minutes p95 and the channel status is updated (suppressed/invalid) per policy. Given a recipient opts out via STOP/UNSUBSCRIBE or list-unsubscribe, When received, Then future sends on that channel are suppressed immediately and consent revocation is timestamped and attributed to source. Given three or more soft bounces occur within 7 days on a channel, When routing, Then that channel is excluded for 7 days and its deliverability score is downgraded. When no eligible channels remain, Then routing halts and a coordinator alert is created.
Notification Service and Contact Record Integration
Given a nudge is sent or attempted, When events occur, Then message, channel, payload hash, decision rationale, and delivery events are written to CaseSpark Notification Service and linked to the Contact and Matter records. Given preferences are updated on the Contact, When the next routing occurs, Then updated preferences are applied and the change is reflected in the audit entry. Then the consolidated communication history shows a chronological timeline per recipient with filter by channel and message type, and event counts match provider webhooks within ±1 after reconciliation. API calls to Notification Service achieve p95 latency < 300ms under nominal load; transient failures are retried with exponential backoff and moved to a dead-letter queue after 3 failed attempts.
Coordinator Oversight Console
"As an intake coordinator, I want a console to review and override nudges so that I can handle edge cases and sensitive situations appropriately."
Description

Provides staff with a real-time console to view, search, and manage all scheduled and sent nudges by matter, contact, language, channel, and status. Supports pausing/resuming campaigns, editing message variables within template constraints, triggering one-off manual nudges, and setting case-level quiet hours or safety holds. Displays conversation context, delivery outcomes, and pending actions with role-based permissions and full audit trails. Integrates with intake and document assembly views to show exactly which fields or approvals are outstanding, enabling human intervention when needed. Expected outcome: transparency and quick control for coordinators without sacrificing automation benefits.

Acceptance Criteria
Real-time Nudge Visibility & Search
Given a user with Nudge.View permission, when they open the console and apply filters by matter, contact, language (ISO 639-1), channel, and status, then the result set contains only matching nudges and loads in ≤2 seconds for up to 10,000 records. Given a free-text search term (matter ID, email substring, or phone digits), when search is executed, then results include exact and partial matches (normalized E.164 for phone) and exclude non-matching records. Given the user’s profile timezone, when timestamps are displayed, then all scheduled/sent times render in that timezone with a tooltip showing UTC. Given pagination set to 50 per page, when navigating pages, then no results are duplicated or skipped and the total count reflects applied filters. Given a live data feed, when new nudges matching the active filters are created or updated, then the list reflects changes within 5 seconds without a full page reload.
Campaign Controls: Pause/Resume, Quiet Hours, Safety Holds
Given an active nudge campaign for a matter, when a Coordinator clicks Pause and confirms, then all pending messages in that campaign move to Paused state and no sends occur during the pause. Given a paused campaign, when Resume is confirmed, then pending messages are re-queued to the next allowed send window respecting case quiet hours and channel throttling rules. Given case-level quiet hours (e.g., 20:00–08:00 local), when a message’s scheduled time falls inside quiet hours, then it is deferred to the next allowable window and the UI shows a “Deferred by Quiet Hours” badge. Given a Safety Hold is enabled for a matter, when any auto or manual send is attempted, then the system blocks the send, displays the hold reason, and logs the attempt; only users with SafetyHold.Override may proceed after providing a reason. Given any control change (Pause, Resume, Quiet Hours, Safety Hold), when saved, then the action requires confirmation, creates an audit entry (who, when, what, reason), and updates the campaign status badge immediately.
Edit Message Variables Within Template Constraints
Given a scheduled nudge instance with a locked template and editable variables, when a Coordinator opens Edit, then only variable fields are editable and the template body remains read-only. Given variable validation rules (required, type, max length, regex), when the user saves, then invalid values are rejected with inline errors and valid values save successfully. Given a selected language, when preview is generated, then the preview renders the final message exactly as it will send (including variable interpolation and locale-specific formats) for the chosen channel. Given a restricted variable (e.g., approval_link), when the value is changed, then the system validates token integrity and domain allowlist before allowing save. Given an edit is saved, when viewing audit, then an entry shows before/after variable values, user, timestamp, and IP, scoped to that nudge instance.
One-off Manual Nudge Sending
Given a matter and contact, when a Coordinator selects a template, channel, and language and clicks Send, then the system interpolates variables, passes validation, and dispatches the message within 2 seconds, recording a Sent event. Given case quiet hours are in effect, when Send is clicked during quiet hours, then the system blocks sending by default, offers a documented override (if user has QuietHours.Override), and requires a reason to proceed. Given the selected template lacks a translation for the chosen language, when Send is attempted, then the system prevents sending and prompts to select an available language. Given channel capabilities (e.g., SMS character limits, email subject required), when composing, then the UI enforces channel-specific constraints and shows a delivery-safe preview. Given the message is sent, when the provider returns status updates, then Delivered/Failed/Bounced events appear in the thread within 5 seconds, linked to the one-off nudge.
Conversation Context & Delivery Outcomes
Given a matter and contact thread view, when opened, then the console displays the last 90 days of messages across all channels in chronological order with sender, timestamp, and content. Given provider webhooks for delivery, when status updates arrive, then each message shows a status badge (Queued, Sent, Delivered, Read/Seen if supported, Failed, Bounced) and any provider error code/message. Given a failed message with a retryable error, when a Coordinator clicks Retry, then a new send attempt is queued with a link back to the original and both attempts are audit-logged. Given attachments in supported formats, when viewing the thread, then thumbnails/previews render; unsupported attachments show a secure download link. Given a search within the thread, when a keyword is entered, then matching messages are highlighted and non-matching are de-emphasized without altering order.
Role-Based Permissions & Audit Trail
Given role permissions, when a user without Nudge.Manage attempts to pause/resume, edit variables, or send a one-off, then the action controls are disabled and server-side enforcement blocks any direct API attempt with 403. Given a user with Nudge.View only, when accessing the console, then they can view threads and statuses but cannot modify campaigns, variables, quiet hours, or safety holds. Given an Admin or Coordinator with appropriate permissions, when they perform any state-changing action, then an immutable audit record is captured with user, role, timestamp, IP, action, target, before/after, and reason (if provided). Given audit filtering, when a date range, user, or action type is selected, then only matching audit entries display and can be exported to CSV within the applied scope. Given compliance requirements, when audit data is viewed, then it is read-only and shows tamper-evident checksums for each entry.
Integration With Intake & Document Assembly
Given an active intake or document assembly for a matter, when viewing the console, then a panel lists outstanding fields/approvals with their owning party and due state. Given a listed outstanding item, when the user clicks View Details, then the system deep-links to the exact intake/document step in a side panel without leaving the console. Given a template that references outstanding items (e.g., approval_link or missing_field_name), when selected for a nudge, then variable values are auto-populated from the current intake state and validated before send. Given an outstanding item is completed by a party, when the intake state updates, then the console reflects the change within 5 seconds and removes the item from the Outstanding list. Given no outstanding items remain, when viewing the panel, then it displays an All Caught Up indicator and disables related reminder templates by default.
Nudge Analytics & A/B Testing
"As a practice owner, I want visibility into which nudges work best so that we can optimize workflows and improve completion without adding staff workload."
Description

Implements dashboards and data pipelines to measure nudge performance: send/deliver/open/click rates, completion of targeted steps, time-to-complete, drop-off points, and escalation effectiveness. Supports A/B and multivariate tests across tone, timing, channel, and template variants with statistical significance calculations. Provides segmentation by matter type, jurisdiction, language, and user profile while preserving privacy. Exposes insights and recommendations to refine orchestration rules and templates. Integrates with CaseSpark reporting and exports to BI tools. Expected outcome: continuous optimization that boosts completion rates and reduces manual follow-ups over time.

Acceptance Criteria
Funnel Metrics Dashboard
Given nudge events are captured with types {sent, delivered, opened, clicked, step_completed, escalated} And a user selects a date range (up to 180 days) and filters by matter type, jurisdiction, language, channel, and template When the Nudge Analytics dashboard loads Then it displays counts and rates: delivery=delivered/sent, open=opened/delivered, click=clicked/opened, completion=step_completed/sent, escalation_effectiveness=step_completed within 72h of escalation / escalated And it displays median and p90 time-to-complete per targeted step And it visualizes drop-off by step with top 3 failure reasons per step And timestamps respect the viewer’s time zone and selectable time windows (hour/day/week) And data refresh SLA is p95 <= 15 minutes from event time And all metric totals match raw event queries within 1% tolerance over the selected range
Event Pipeline Reliability & Latency
Given event producers may retry sends and deliveries When duplicate events arrive within a 24-hour window Then the pipeline de-duplicates using idempotency keys and source timestamps And end-to-end ingestion-to-warehouse latency is p95 <= 10 minutes and p99 <= 30 minutes under nominal load And validated events meet a versioned schema with required fields {event_type, nudge_id, recipient_id, timestamp, channel, language} And invalid events are quarantined with error codes and visible in an operator report within 5 minutes And daily event loss is < 0.1% measured by producer vs. warehouse reconciliation And historical backfills can run without double-counting, verified by invariant checks on nudge_id+event_type
A/B & Multivariate Experiment Setup
Given a product owner creates an experiment varying tone, timing, channel, and template And defines control plus up to 8 variants with allocation ratios When the experiment is activated with targeting rules and a primary metric (Step Completion within 7 days) Then recipients are randomly assigned at the recipient level with assignment persisted across sessions And stratified sampling is supported by jurisdiction and language to balance arms And minimum sample size per variant is enforced (>= 500 recipients or power >= 0.8 at alpha=0.05) And overlapping experiments on the same audience/primary metric are prevented or require an explicit override with documented risk And start/stop schedules are supported with automatic early-stop for harm when a variant is >=10% worse than control with p<=0.01 for the primary metric
Statistical Significance & Results Reporting
Given an experiment has reached minimum sample size and completed its observation window When a user views results Then the system reports effect size, 95% confidence intervals, and two-tailed p-values (alpha=0.05) for the primary metric And adjusts for multiple comparisons across variants using Holm-Bonferroni for frequentist results And provides Bayesian 95% credible intervals and probability of superiority as secondary And identifies the winner/loser per pre-registered success criteria and minimum detectable effect And displays segment-level lifts (matter type, jurisdiction, language) with suppression for small cohorts And allows export of anonymized summaries (CSV/JSON) including metadata: sample sizes, observation window, analysis method, version
Privacy-Preserving Segmentation & Access Control
Given an Analyst applies segments by matter type, jurisdiction, language, and user profile When results are rendered or exported Then no PII (names, emails, phone numbers, addresses, free-text) is displayed or included; only aggregated counts and rates And cohorts with n<20 are suppressed or noise-added (±1–3) with differential privacy epsilon<=1.0 for public/shared views And per-case and recipient identifiers are irreversibly hashed with rotation; raw identifiers are never exposed in UI or exports And RBAC restricts raw event table access to Admins; Analysts only access aggregated views And all access and exports are audited with user, time, filters, row counts, and destination retained for >= 1 year
Insights & Orchestration Recommendations
Given at least 4 weeks of nudge data and one or more completed experiments When the system detects statistically significant uplift or degradation for any variant or rule Then it generates ranked recommendations with estimated uplift, confidence, impacted templates/rules, and suggested next steps (promote, retire, iterate) And supports one-click application to orchestration rules with preview of affected audiences and rollback within 1 click And creates a tracked change record including diff, approver, expected KPI impact, and start time And measures realized impact vs. baseline over a 14-day post-change window and reports attribution in the dashboard
Reporting Integration & BI Exports
Given a user opens CaseSpark Reporting and selects Nudge Analytics When viewing dashboards Then charts conform to platform theming and inherit permissions from CaseSpark roles And scheduled weekly exports deliver to a configured S3 bucket and HTTPS endpoint in Parquet and CSV with a published schema and data dictionary And a REST API provides paginated, filtered summaries with rate limiting and API keys And exports and API exclude PII and respect cohort suppression rules And scheduled exports complete within 30 minutes of the scheduled time with retries (3x, exponential backoff) and success/failure notifications

JointDoc Builder

Merge agreed facts directly into jurisdiction‑aware joint petitions, parenting plans, and settlement agreements. Unresolved discrepancies insert neutral placeholder clauses and request targeted confirmations, producing e‑sign‑ready packets faster with fewer drafting loops.

Requirements

Structured Fact Merge Engine
"As a family-law attorney, I want agreed facts from intake to auto-populate joint documents so that I can draft filings quickly without retyping and reduce errors."
Description

Implement an engine that maps normalized intake data (parties, children, property, support terms, dates, orders) into jurisdiction-aware templates for joint petitions, parenting plans, and settlement agreements. Supports conditional sections, computed fields (e.g., parenting time totals), repeatable tables, and formatting rules. Provides versioned mapping files per jurisdiction and document type, validation for required fields before merge, and graceful handling of nulls. Integrates with CaseSpark’s intake graph and template service, exposing an API to generate draft documents on demand and a UI preview with field-level highlights.

Acceptance Criteria
Jurisdiction‑Aware Mapping Selection
Given a matter with jurisdiction "CA" and documentType "Joint Petition" And mapping version "v1.2.0" is marked Active for CA/Joint Petition When the merge API is called with the matterId Then the engine loads mapping file key "CA/Joint Petition/v1.2.0" And applies all CA-specific conditional sections as defined in that mapping And writes mappingVersion="CA-JointPetition-v1.2.0" into the document metadata And the produced document includes the CA-specific captions, signature blocks, and required advisements
Required Field Validation Before Merge
Given the required field set for "Joint Petition" includes petitioner.fullName, respondent.fullName, marriage.date And the intake graph for the matter is missing respondent.fullName When the merge API is called Then the API responds 422 Unprocessable Entity And the response body contains code="REQUIRED_FIELDS_MISSING" and fields=["respondent.fullName"] And no document is generated (no documentId issued) And a validation banner renders in UI preview listing "Respondent full name is required"
Computed Parenting Time Totals
Given a parentingPlan schedule of 52 weeks with motherOvernightsPerWeek=4 and fatherOvernightsPerWeek=3 When a Parenting Plan document is generated Then computed field motherOvernightsPerYear equals 208 And computed field fatherOvernightsPerYear equals 156 And percentage fields motherShare equals 57.14% and fatherShare equals 42.86% And these values are formatted per locale "en-US" with no trailing zeros beyond two decimal places
Repeatable Tables for Children and Property
Given children=[{name:"Ava", dob:"2018-05-01"}, {name:"Ben", dob:"2016-02-10"}] And the mapping specifies sort=dob ascending And maritalProperty=[{type:"Vehicle", description:"2017 Honda Civic"}, {type:"Account", description:"Checking 1234"}] When a Settlement Agreement is generated Then the Children table renders 2 rows ordered Ben, Ava And the Property table renders 2 rows in input order (no sort rule defined) And headers appear once per table and repeat on new pages as needed And no blank rows are added and no orphan headers occur at page end
Graceful Null Handling and Placeholders
Given optional fields petitioner.middleName=null and respondent.secondaryAddress=null And the template marks middleName as inline optional and secondaryAddress section as conditional And the mapping specifies a placeholder clause for missing support terms When a Joint Petition is generated Then the parties' names render without extra spaces (e.g., "Jane Doe") And the Secondary Address section is omitted And the Support Terms section includes the configured placeholder clause tagged NEEDS_CONFIRMATION in metadata.placeholders
On‑Demand Merge API Contract and Performance
Given a valid merge request with Idempotency-Key "abc123" and a 25-page output When POST /v1/merge is called Then the API responds 201 with JSON including documentId, mappingVersion, processingTimeMs And processingTimeMs is less than or equal to 3000 And a second identical request within 24h returns 200 with the same documentId (idempotent) And concurrent requests beyond 20 per minute per account receive 429 with code="RATE_LIMIT_EXCEEDED"
UI Preview Field‑Level Highlights
Given a generated draft document with 2 missing required fields and 3 computed fields When the user opens the UI preview Then missing required fields are highlighted in red and listed in a side panel with their source paths And computed fields are highlighted in blue with displayed formulas and final values And clicking a side panel item scrolls and highlights the corresponding field in the document And a toggle allows showing/hiding placeholder clauses, defaulting to show
Jurisdiction-Aware Template Selection
"As an attorney practicing across counties, I want the system to pick the right joint document format and clauses automatically so that my filings meet local requirements without manual research."
Description

Integrate with CaseSpark’s rules engine to automatically select the correct joint document variants per state/county and case subtype, including required clauses, captions, signature blocks, notary pages, attachments, filing codes, and page layout standards. Enforce compliance checks pre-merge (e.g., mandatory parenting class language, statute citations) and post-merge (page/field validations). Maintain a registry of template metadata (effective dates, court IDs, revision history) and failover to last-known-good versions with change alerts when courts update forms.

Acceptance Criteria
Auto-Select Template by Jurisdiction and Case Subtype
Given a case intake with state, county, and case subtype captured And valid rules engine mappings exist for that combination When the user initiates JointDoc Builder document generation Then the system automatically selects the correct joint document variant And displays the selected variant name, court ID, and version number to the user And disallows manual selection of variants outside the identified jurisdiction and subtype And if no mapping exists, the system blocks generation and displays an actionable error with the missing mapping details And the selection rationale (rules path) is logged with the case ID
Required Components Included for Selected Jurisdiction
Given a selected jurisdiction-aware joint document variant When the system prepares the template for merge Then the template includes all required clauses, captions, signature blocks, notary pages, attachments, filing codes, and page layout standards defined for that jurisdiction And a completeness check confirms 100% presence of required components before merge And any missing component is listed with severity and prevents merge until resolved
Pre-Merge Compliance Checks Enforced
Given a selected template variant with jurisdiction-specific mandates When pre-merge compliance checks run Then the system verifies presence of mandatory parenting class language where applicable And validates statute citations for required format and currency against the rules engine And confirms required court identifiers and filing code applicability And any failed check blocks merge and presents a checklist of failed items with guidance links And all check results (pass/fail, rule ID, timestamp) are stored on the case
Post-Merge Page and Field Validation
Given a merged joint document packet When post-merge validations execute Then all required fields are populated and no unresolved placeholders remain And page layout conforms to jurisdiction standards for margins, caption position, font size, and page count limits And filing code values conform to the court’s accepted code list and schema And validation results are viewable with rule-level pass/fail and affected field references And any failure prevents e-sign packet creation and filing export
Template Metadata Registry and Governance
Given a template variant is created or revised When it is saved to the template registry Then required metadata fields must be present: template ID, court ID, jurisdiction (state and county), case subtype(s), effective start date, revision number, author, change log summary, and source reference And the system prevents deployment without required metadata And revision history is immutable, versioned, and viewable with timestamps And queries by court ID and effective date return the correct active version
Failover to Last-Known-Good with Change Alerts
Given a court updates a form and the new template version is not yet validated When the system detects an update event or an administrator marks the current template as outdated Then document generation automatically uses the last-known-good version for that jurisdiction and subtype And the system generates change alerts to designated administrators and displays an in-app banner to affected users And all generated packets during failover record the fallback version used in the audit log And the system switches to the new validated version only after compliance checks pass and activation is confirmed
Discrepancy Resolution Workflow
"As a paralegal, I want conflicts between party inputs flagged with neutral language auto-inserted and targeted confirmations requested so that I can finalize documents with minimal back-and-forth."
Description

Detect conflicts and gaps between party responses by comparing structured answers and evidence (e.g., differing incomes, custody schedules). Automatically insert neutral placeholder clauses where unresolved, and generate targeted confirmation tasks with micro-questions to the correct party (or both) to resolve discrepancies. Provide a resolution panel showing conflicted fields, suggested neutral language, risk notes, and one-click apply/override. Support iterative refresh of the draft with tracked resolutions and a history log.

Acceptance Criteria
Income Discrepancy Auto-Detection & Placeholder Insertion
Given the matter jurisdiction is set and both Party A and Party B have provided gross monthly income And the absolute difference between the two values is >= the greater of 1% of the higher value or $50 (default threshold, configurable) When the discrepancy engine runs on save or via manual trigger Then the field "gross_monthly_income" is flagged as Conflict in the resolution panel with both values and source timestamps And a jurisdiction-aware neutral placeholder clause for income is inserted in the joint petition and settlement agreement at the correct sections And the draft packet status changes to Requires Resolution and e-sign dispatch is blocked with a validation message listing the unresolved field And the detection event is logged with timestamp, actor "system", discrepancy id, and threshold used
Parenting Time Schedule Conflict Handling
Given both parties have submitted structured weekly custody schedules And at least one day/time block differs between the parties When the discrepancy engine runs Then each conflicting block is itemized as a separate discrepancy labeled by day and segment (e.g., "Monday Overnight") And a neutral placeholder clause summarizing unresolved schedule items is inserted into the parenting plan with bracketed fields for each conflicting block And parenting plan preview highlights placeholder sections and disables calendar export until all schedule discrepancies are resolved And the discrepancy list includes a count of conflicting blocks and variance notes (e.g., hours/week delta)
Evidence-Based Discrepancy Detection from Documents
Given a user uploads evidence (e.g., paystub) and data extraction for a relevant field has confidence >= 0.80 And the extracted value differs from the party-entered value by >= the greater of 1% or $50 When the discrepancy engine runs Then the field is flagged as Evidence Conflict with a link to the evidence file and highlighted snippet And the suggested neutral clause references documentation pending confirmation and includes the variance amount and percentage And a risk note is displayed indicating evidence source, extraction confidence, and date
Targeted Confirmation Tasks with Micro-Questions
Given a discrepancy exists and field ownership rules identify the responsible party role (Party A, Party B, or Both) When the system generates confirmation tasks Then a task is created per discrepancy with a due date 48 hours from creation (configurable) and a clear title referencing the field And the task contains 1–5 micro-questions with validated input types matching the field and optional evidence upload And notifications are sent to assignees through configured channels within 2 minutes of task creation And completing the task updates the resolution panel within 5 seconds and closes the task And tasks for Both are split into two assignee-specific tasks with independent completion states
Resolution Panel with Suggested Language, Risk Notes, and Apply/Override
Given one or more discrepancies exist When the user opens the resolution panel Then each discrepancy row displays field label, Party A value, Party B value, extracted evidence value (if any), variance, suggested neutral clause text, and risk notes And clicking Apply Suggested updates the draft immediately and marks the discrepancy as Resolved And clicking Override allows entry of custom clause text, requires a reason, and updates the draft And each action records user id, timestamp, old/new clause text, action type (apply/override), and reason in the history log
Iterative Draft Refresh with Tracked Resolutions and History Log
Given at least one discrepancy is resolved or new answers/evidence are submitted When the user triggers Refresh Draft or autosave runs Then the draft regenerates within 10 seconds and replaces relevant placeholders with resolved text across all affected documents And track-changes markup highlights added/removed text and a Compare view is available between the last two versions And resolved discrepancies are archived with status Resolved and linked to the draft version id(s) And unresolved discrepancies persist as placeholders in the draft and as Open items in the panel
Jurisdiction-Aware Neutral Language Selection and Fallback
Given the matter jurisdiction is selected and mapped to a clause library When the system inserts a placeholder clause for a discrepancy Then it selects neutral language from the jurisdiction’s library that complies with local requirements for joint petitions and parenting plans And if no jurisdiction-specific clause exists, a generic neutral clause is inserted, flagged Generic, and surfaced in the panel with a Review suggestion And the inserted clause uses correct defined terms and citation formats for the selected jurisdiction
Neutral Placeholder Clause Library
"As a solo attorney, I want reusable, jurisdiction-appropriate neutral clauses so that I can keep drafts moving safely when clients haven’t agreed on every detail."
Description

Maintain a curated, jurisdiction-keyed library of neutral placeholder clauses tied to discrepancy categories (e.g., support amount TBD, exchange location TBD, holiday schedule pending). Allow firm-level customization, approvals, and version control with effective date ranges and fallback hierarchies (court > state > firm default). Include tagging for tone (neutral, conciliatory) and risk warnings. Integrate with the merge engine to select the best-fit clause based on context and to update documents when a placeholder is resolved.

Acceptance Criteria
Jurisdiction Fallback Clause Selection
- Given a discrepancy category "Support Amount TBD" and a matter in Court "King County Superior Court" (State: WA) with merge date 2025-09-10, When the library has an Approved court-level clause A (effective 2025-01-01..2025-12-31), a state-level clause B (effective 2024-01-01..2025-12-31), and a firm-default clause C, Then clause A is selected and inserted. - Given no court-level clause exists but an Approved state-level clause is active for the merge date, When selecting a placeholder, Then the state-level clause is selected. - Given neither court nor state-level clauses are active for the merge date, When selecting a placeholder, Then the Approved firm-default clause is selected. - Given no Approved clause is active at any level for the merge date, When selecting a placeholder, Then the merge is blocked, an error code "NoActivePlaceholderClause" is logged, and the drafter sees a blocking alert identifying the category and jurisdiction.
Effective Dates and Version Control Enforcement
- Given a clause has versions v1 (Approved, effective 2025-01-01..2025-06-30) and v2 (Approved, effective 2025-07-01..open), and the merge date is 2025-09-10, When selecting a placeholder, Then v2 is used. - When a user edits a clause, Then a new version is created with incremented semantic version (e.g., 1.2 -> 1.3), immutable snapshot of prior versions is preserved, and a required change summary is stored. - When a future-dated version exists (start date > today), Then it is not eligible for selection until its start date. - When a version is deactivated, Then it is immediately excluded from selection and the audit log records user, timestamp, and reason.
Approval Workflow and Role Restrictions
- When a new clause version is created, Then its status is Draft and it is ineligible for merge selection until Approved by a user with role "Managing Attorney" or configured approver role. - When a Draft or Pending clause is the only available candidate for a category/jurisdiction, Then merge selection fails with error code "NoApprovedClause" and the UI shows the approver(s) required. - When a clause version is Approved, Then the approval record captures approver ID, timestamp, and optional note and is visible in the clause history. - Users without editor privileges cannot modify clause text, tags, or effective dates; they may view and propose edits as Suggestions without altering Approved content.
Tone and Risk Tag Compliance
- Given a matter preference "Tone = Conciliatory" and multiple eligible clauses exist, When selecting a placeholder, Then a clause tagged "Conciliatory" is chosen; if none exist, Then a "Neutral" tone clause is chosen and the selection rationale notes the fallback. - When the selected clause contains risk tags (e.g., "FinancialExposure"), Then a non-blocking inline risk banner is displayed to the drafter with tag names and a link to guidance, and the event is recorded in the audit log. - When filtering the clause library by tags, Then results are limited to clauses containing all selected tags and the UI displays the count of matches.
Context-Aware Merge and Field Interpolation
- Given document type = "Parenting Plan" and discrepancy category = "Exchange Location TBD", When merging, Then the clause mapped to (doc type: Parenting Plan, category: Exchange Location TBD) is selected over a general category-only clause if both are eligible. - When inserting the placeholder, Then dynamic tokens (e.g., {partyA}, {partyB}, {childrenNames}, {jurisdictionName}) are interpolated with current matter data, and unresolved tokens are flagged with error code "UnresolvedToken". - Then the clause is inserted at the configured section anchor for the jurisdiction template and inherits the document’s numbering and formatting rules. - Then each inserted placeholder is assigned a unique ID and stored in the document manifest for subsequent resolution updates.
Placeholder Resolution and Document Update
- Given a placeholder with ID PH-123 exists in multiple documents of a packet, When the discrepancy is resolved with value "Drop-off at City Hall, Saturdays 10:00 AM", Then all occurrences are updated in a single operation, the documents re-render, and PDFs regenerate successfully. - Then the system records before/after text diffs, resolver ID, timestamp, and resolution values in the audit trail and marks PH-123 as Resolved. - When resolution fails in any document, Then no documents are partially updated, an error code "ResolutionApplyFailed" is logged, and the packet remains in its pre-update state (transactional integrity).
Deterministic Tie-Breaking and Selection Traceability
- Given multiple Approved clauses at the same hierarchy level with overlapping effective ranges, When selecting a placeholder, Then the engine applies tie-breakers in order: latest approval timestamp, then highest semantic version, then lowest lexicographic clause ID. - Then the engine stores a selection rationale object containing: input context (jurisdiction, doc type, category, tone), candidate list with eligibility checks, hierarchy path taken, tie-breaker decisions, and final chosen clause ID; this object is retrievable via API and visible in a UI inspector. - When the same context is evaluated again, Then the selected clause is identical to prior runs (idempotent selection).
E-Sign Ready Packet Assembly
"As an attorney, I want the generated documents to be immediately e-signable and properly routed so that I can send, collect, and file without manual setup."
Description

Assemble e-sign-ready packets from merged outputs, including exhibits, parenting plan attachments, financial affidavits, and jurisdiction-specific cover sheets. Auto-place signature, initial, and notary fields for all signers in correct order, supporting simultaneous or sequential signing and per-document routing rules. Integrate with e-sign providers and return signed PDFs with certificate of completion. Validate signer identity and ensure packets meet filing size and format constraints. Expose status updates and resend flows within CaseSpark.

Acceptance Criteria
Packet Assembly Includes All Required Documents and Jurisdiction Cover Sheets
Given a matter with at least one merged JointDoc output and at least one exhibit, parenting plan attachment, and financial affidavit uploaded, and a jurisdiction is selected When the user clicks Assemble E‑Sign Packet Then the system creates a draft packet containing all required documents defined by the selected jurisdiction’s packet profile, including cover sheets, and excludes any documents not applicable And documents appear in the exact order defined by the profile And each document filename conforms to "{MatterID}_{DocCode}_{Version}.pdf" And the packet is generated and previewable within 10 seconds for packets up to 200 pages total And the draft packet is saved and can be reopened with no content loss
Auto‑Placement of Signature, Initial, and Notary Fields for All Signers
Given at least two signers with roles (e.g., Petitioner, Respondent, Notary) are defined And document templates contain placement anchors for required fields When the packet is assembled Then signature, initial, date, and notary fields are auto-placed at their anchors on every applicable document And each field is assigned to the correct signer based on role mapping And jurisdiction-required notary blocks are inserted on documents marked "Requires Notary" And validation reports 0 unplaced required fields and 0 unassigned required fields And if any anchors are missing, the system blocks send and lists the missing fields by document and page
Sequential and Simultaneous Signing with Per‑Document Routing
Given a packet with two signers (A and B) and per-document routing rules (Doc1: A then B, Doc2: A only) When the packet is sent with sequential signing enabled Then Doc1 is delivered to A first and to B only after A completes Doc1 And Doc2 is delivered to A immediately and never to B And when simultaneous signing is enabled, documents configured for "Any Order" are delivered to both A and B at the same time And reminders and expirations use the configured cadence (e.g., 3-day reminders, 14-day expiration) And if any signer declines, the packet status becomes "Declined" and routing halts with an audit entry
E‑Sign Provider Integration Returns Signed PDFs and Certificate of Completion
Given an active connection to the selected e-sign provider and a valid callback endpoint When the packet is sent Then an envelope is created with all mapped fields and recipients without schema errors And provider status webhooks update the packet in CaseSpark to Sent, Delivered, Completed, Declined, or Voided within 30 seconds of receipt And upon completion, all signed PDFs are returned, flattened, and stored in the matter with a certificate of completion (single combined PDF or separate certificate file per provider capability) And the system surfaces provider errors to the user with actionable messages and automatically retries transient failures up to 3 times with exponential backoff
Signer Identity Verification Enforced per Jurisdiction and Policy
Given identity verification is required (e.g., SMS OTP or KBA) per the packet policy or jurisdiction When invitations are sent Then each signer receives the configured verification challenge before accessing any document And SMS OTP requires a correct 6-digit code within 3 attempts and expires after 10 minutes And KBA requires a passing score per provider policy; failures lock the signer out for 30 minutes And verification results (pass/fail, method, timestamp) are stored in the audit log and included in the completion certificate when available And if verification fails, the signer cannot view or sign documents and the sender can re-initiate verification via Resend
Filing Size and Format Constraints Validation and Optimization
Given the selected jurisdiction profile defines filing constraints (e.g., PDF/A-1b, Letter size, max file 5 MB, max packet 35 MB) When the packet is assembled Then all documents are converted to compliant PDF/A and form fields are flattened And images are downsampled/compressed to meet size limits without reducing legibility below 300 DPI And if the total packet exceeds the max size, non-core attachments are split into numbered volumes automatically And the system blocks send if any document remains noncompliant, listing each violation with suggested fixes
In‑App Signing Status Updates and Resend/Recovery Flows
Given a packet has been sent When a user opens the CaseSpark matter view Then real-time statuses are displayed per document and signer (Not Sent, Sent, Viewed, Completed, Declined, Failed) with last activity timestamps And the user can resend an invitation to a signer, up to 3 times per 24 hours, with optional email/phone correction And a resend triggers identity verification again if enabled And all actions (resend, email change, cancel, void) are captured in an immutable audit log And if delivery fails (bounce/unreachable), the UI surfaces the failure reason and blocks further resends until the address is corrected
Redline, Provenance, and Audit Export
"As an attorney, I want redlines and provenance for every clause so that I can explain changes, satisfy compliance inquiries, and collaborate efficiently with counterparties."
Description

Provide redline comparison between document versions and export to Word/PDF with tracked changes for external review. Maintain field-level provenance showing whether content was auto-merged, chosen from a clause library, or manually edited, including who, when, and why. Offer an immutable audit log for compliance, with filters by party, clause, and jurisdiction rule. Enable one-click generation of a disclosure packet for opposing counsel or court showing agreed vs pending items.

Acceptance Criteria
Redline View Between Document Versions
- Given a matter with at least two saved versions of a document, when the user selects Version A and Version B and clicks Compare, then a redline view renders insertions, deletions, and moved text with inline change bars and a summary count by change type. - Given the redline view is open, when the user toggles Show Formatting Changes off, then only content changes are displayed and formatting-only changes are hidden. - Given a 50-page document with up to 2,000 tracked changes, when Compare is triggered, then the redline view loads within 2 seconds in 95% of trials. - Given the redline summary pane is visible, when the user clicks any listed change, then the document scrolls to and highlights the corresponding change within 300 ms.
Tracked Changes Export to Word and PDF
- Given a redline between two versions, when the user exports to Word (.docx), then the file opens in Microsoft Word with Track Changes enabled and all insertions/deletions preserved exactly as shown in the app. - Given the same redline, when the user exports to PDF, then the PDF visually preserves strikeouts/underlines and includes a first-page change summary table. - Given export settings with Include Comments disabled, when exporting, then no internal comments or provenance notes are embedded in the file metadata or content. - Given a 100-page document, when exporting to Word or PDF, then the export completes within 10 seconds and the file size does not exceed 20 MB.
Field-Level Provenance Capture and Display
- Given an auto-merged field sourced from intake data, when the document is generated, then the field shows provenance type Auto-Merged with source record ID, author System, and UTC timestamp. - Given a clause inserted from the library, when it is added, then provenance records type Clause-Library with clause ID and version, the inserting user ID, and UTC timestamp. - Given a manual edit to any field, when the user saves, then a reason (minimum 5 characters) is required and stored with editor user ID and UTC timestamp. - Given the provenance panel is open, when the user hovers a field, then a tooltip displays type, who, when, and reason within 300 ms.
Immutable Audit Log with Advanced Filters
- Given any provenance or redline event occurs, when it is recorded, then an append-only audit entry is written with a cryptographic hash linking to the prior entry (hash chain) and a server-side signature. - Given the audit log UI, when filtering by party=Respondent, clause=Parenting Time, jurisdiction=CA, and a date range, then only matching entries are returned with accurate counts and paginated results. - Given a filtered audit view, when the user exports to CSV, then the exported file contains exactly the same filtered subset and includes hash, signature, user ID, and timestamp columns. - Given an attempt to delete or edit an audit entry via UI or API, when executed, then the operation is rejected with HTTP 403 (API) or disabled controls (UI), and a new audit event records the denied attempt.
One-Click Disclosure Packet Generation
- Given a matter with agreed and pending items, when the user clicks Generate Disclosure Packet, then a single PDF is produced with sections: Agreed Terms, Pending Items, and Neutral Placeholder Clauses for unresolved items. - Given packet settings with Exclude Internal Notes enabled, when generated, then internal comments and provenance reasons are omitted from the packet and file metadata. - Given a 75-page packet, when generation is triggered, then the PDF is ready within 8 seconds, contains a table of contents and page numbers, and passes PDF/A-2b validation. - Given links to jurisdiction rules and clauses are included, when the packet is opened, then links resolve to share-safe, view-only URLs without requiring authentication for 14 days.
Change Acceptance/Rejection Synchronizes to Base Document
- Given a redline view is open, when the user accepts a specific change, then the base document updates to include the change and the redline counters update within 300 ms. - Given a redline view is open, when the user rejects a specific change, then the base document removes/reverts the change and provenance records the rejection with user ID, UTC timestamp, and reason (optional). - Given the batch action Accept All Formatting Changes is executed, then only formatting changes are accepted and all content changes remain pending. - Given an accepted/rejected change, when exporting to Word/PDF thereafter, then the exported file reflects the current acceptance state exactly.

ThreadMapper

Turns SMS and WhatsApp conversations into structured intake automatically. Detects answers, dates, addresses, and parties as clients text, maps them to your intake fields, and flags what’s still missing. Lets After‑Hours responders and Mobile‑First attorneys convert whole chat threads into a completed intake without retyping—speeding first touch to engagement.

Requirements

SMS & WhatsApp Channel Ingestion
"As an after-hours responder, I want incoming SMS/WhatsApp messages to automatically appear as a single conversation linked to the caller’s contact so that I can continue intake without switching tools or retyping."
Description

Implement secure, reliable ingestion of SMS and WhatsApp conversations into CaseSpark. Integrate with telephony providers and WhatsApp Business API using webhooks to capture inbound/outbound messages, timestamps, sender IDs, and media. Normalize threads by contact and matter, handle long messages, retries, and rate limits, and preserve message ordering across time zones. Support opt-in/opt-out keywords, delivery receipts, and number pooling. Map each message to the correct intake session so conversations can be processed by ThreadMapper without manual copying, ensuring first-touch continuity from chat to intake.

Acceptance Criteria
Inbound SMS Capture & Signature Verification
Given a valid inbound SMS webhook request with provider signature and payload containing from, to, body, message_id, timestamp, and media references When the webhook endpoint receives the request Then the signature is verified and a 200 response is returned within 2 seconds And the message is persisted once with normalized fields (channel=SMS, from E.164, to E.164, body, provider_message_id, received_at UTC, attachments metadata) And any media (MMS) is fetched and stored with a durable URL, content-type, and size And redacted logging prevents storage of full message bodies or media URLs in plaintext logs And an intake routing event is enqueued referencing the persisted message id within 500 ms
WhatsApp Business Ingestion (Text, Media, and Metadata)
Given a WhatsApp Business webhook signed with X-Hub-Signature-256 containing sender wa_id, recipient phone_number_id, message id, timestamp, and content (text/media/location/contact) When the webhook endpoint receives the event Then the signature is verified and a 200 response is returned within 5 seconds And the message and its content are persisted with normalized fields (channel=WhatsApp, wa_id, to, provider_message_id, received_at UTC, content type) And referenced media is downloaded via Graph API and stored with durable URL, checksum, and size And unsupported content types are recorded with reason=unsupported without blocking other messages in the batch
Outbound Message Logging & Delivery Receipts
Given an outbound message is sent via a supported provider When the send API returns a provider_message_id Then an outbound message record is created with status=queued or sent, channel, to, from, body, and sent_at UTC When a delivery receipt webhook arrives with the same provider_message_id Then the message status is updated to delivered or failed with provider error code and delivered_at or failed_at timestamps And duplicate receipts do not create duplicate status transitions or records
Thread Normalization, Ordering, and Intake Mapping
Given a message (inbound or outbound) is persisted When a thread key is computed using canonical participant identifiers (client wa_id/phone, business number) and practice context Then the message is associated to the correct intake session if one is open for the contact within the practice And if no intake session exists, the message is placed in an Unmatched bucket and auto-attached when a session is created within 24 hours And all message timestamps are normalized to UTC and original provider timestamps are retained And conversation order is determined by provider timestamp then provider_message_id as a tiebreaker and is stable across retries and time zones And the association result is exposed to ThreadMapper within 1 second of message persistence
Retries, Rate Limits, and Idempotency
Given the provider retries a webhook delivery with the same message id When the webhook is processed Then the operation is idempotent and no duplicate message records are created And a 200 response is returned to stop further retries Given outbound send or media fetch responses indicate rate limiting (HTTP 429) When retry logic executes Then exponential backoff with jitter is applied up to 5 attempts over 15 minutes And 99.9% of rate-limited operations succeed within the retry budget and are recorded in telemetry
Opt-in/Opt-out Compliance and Keyword Handling
Given an inbound SMS containing STOP, STOPALL, UNSUBSCRIBE, CANCEL, END, or QUIT (case-insensitive) When processed Then the contact’s SMS consent state is set to opted_out and a standard compliance confirmation is sent And no further outbound SMS are sent to that number until a valid opt-in keyword (START, YES, UNSTOP) is received Given a WhatsApp inbound message from a contact without recorded opt-in When processed Then the message is ingested but no outbound messages are initiated until consent is recorded per WhatsApp policy And all consent changes are timestamped, channel-scoped, and auditable
Number Pooling & Dynamic From Routing
Given multiple pooled SMS numbers are configured for a practice When replying to an existing thread Then the system selects the same From number previously used with the contact to preserve continuity When initiating a new thread under throughput constraints Then the system selects an available From number that meets provider throughput/10DLC rules and records the selection rationale And inbound messages to any pooled number are routed to the owning practice and mapped to the correct thread based on participant identifiers
Entity Extraction & Intake Field Mapping
"As a mobile-first attorney, I want client details mentioned in chat to auto-populate my intake fields so that I don’t have to manually parse and enter data from messages."
Description

Automatically detect and extract entities (parties, relationships, dates, addresses, emails, phones, children, assets) from freeform chat text and map them to firm-specific intake fields. Provide configurable schemas per practice area and jurisdiction, with normalization (date formats, phone validation, postal address standardization) and role classification (client, spouse, opposing party, minor). Include confidence scoring, explainability anchors back to message snippets, and deterministic fallbacks for critical fields. Make the mapper extensible via rules and synonyms to support custom field labels used by solo and two-attorney family-law practices.

Acceptance Criteria
SMS Thread Entity Extraction (Family Law Intake)
Given a labeled SMS conversation containing names, DOBs, marriage/separation dates, addresses, emails, phones, children, and assets When the thread is processed by ThreadMapper Then the system extracts each entity type with macro F1 ≥ 0.90 on the provided gold test set And each detected entity is associated to its source message id and character span And any required intake field without a mapped value is added to a Missing Information list
Firm-Specific Field Mapping & Synonym Support
Given a configured intake schema with firm-specific field labels and synonyms And given extraction output for a thread When mapping runs Then each extracted entity is mapped to the correct schema field according to rules and synonyms And unmapped entities are surfaced as review items And mapping accuracy on the configuration validation set is ≥ 98% by field And the mapping preserves expected data types (date, phone, address) and formats
Role Classification of Parties
Given mentions of parties in the thread, including relational phrases (e.g., my husband, our child, opposing counsel) When classification runs Then each party is assigned one of [Client, Spouse, Opposing Party, Minor, Other] And overall role assignment accuracy is ≥ 95% on the labeled evaluation set And ambiguous references (confidence < 0.7) are flagged for manual review with rationale And mutually exclusive roles are enforced by rules (e.g., Opposing Party cannot be Minor)
Normalization and Validation of Core Fields
Given extracted dates, phone numbers, and postal addresses When normalization executes Then dates are converted to the firm’s configured format with the original preserved And phone numbers are validated and output in E.164; invalid numbers are flagged And U.S. addresses are standardized to USPS format with ZIP+4 when available; invalid addresses are flagged And overall normalization success rate is ≥ 99% on the normalization test set
Explainability Anchors, Confidence Scoring, and Auditability
Given any mapped field originating from chat text When viewing the intake record Then the UI highlights the exact source snippet with message id and character offsets And each mapped field includes a confidence score between 0.0 and 1.0 And fields with confidence < 0.7 are marked Needs Review And an exportable audit JSON includes field value, confidence, anchor, rule/source, and timestamp for 100% of mapped fields
Deterministic Fallbacks for Critical Fields
Given critical fields [Client Full Name, Jurisdiction (State+County), Case Type, Opposing Party Name] When a critical field is missing or has confidence < 0.7 Then deterministic rules are applied to derive a value And the derived value is tagged with rule id and marked Derived And if still unresolved, the intake status is set to Incomplete and the field appears in the Missing Information list And fallbacks never overwrite a user-confirmed value
Jurisdiction- and Practice-Area Schema Selection
Given practice area Family Law and thread content containing a postal address in Texas When schema selection runs Then the Texas Family Law schema is chosen and logged with schema id and version And field set includes county-specific requirements (e.g., County vs Parish) And for ambiguous jurisdiction mentions, the precedence rule (explicit > address > area code) is applied And selection accuracy across test cases for at least three jurisdictions is ≥ 98%
Missing Data Detection & Smart Prompts
"As a prospective client texting after hours, I want the system to ask me only the missing, relevant questions so that I can complete intake quickly without repeating myself."
Description

Continuously evaluate field completeness and generate targeted follow-up prompts to collect missing or low-confidence information directly in the chat. Use templated, jurisdiction-aware questions (e.g., marriage date, county, case type) and throttle outreach to respect quiet hours and carrier guidelines. Support multilingual prompts, escalation to a human when ambiguity persists, and resume logic across sessions. Surface a checklist of outstanding fields with statuses (missing, inferred, needs confirmation) to shorten the path from first touch to a complete intake.

Acceptance Criteria
Real-time Missing Field Detection in Chat Threads
Given an active SMS or WhatsApp intake thread mapped to a specific intake template When new messages are received and parsed Then each mapped field must be assigned a status of missing, inferred, or needs confirmation based on confidence thresholds where missing = no candidate value, inferred = derived value with confidence ≥ 0.80, and needs confirmation = direct extraction with 0.60 ≤ confidence < 0.90 And the status update and candidate value (if any) must be recorded within 2 seconds of message receipt And each field entry must log value, source message ID(s), confidence score, extraction method, and timestamp
Jurisdiction-Aware Smart Prompts
Given one or more required fields are missing or need confirmation and a jurisdiction can be determined from previously collected data (e.g., party address, selected county) or configured default When the system composes a prompt Then it must select a jurisdiction-specific template for the field (e.g., marriage date, county, case type) and populate placeholders with known context And it must not prompt for any field already confirmed in the session And the prompt must include an example format appropriate to the jurisdiction (e.g., date formats) and validate the reply against that format And upon valid reply, the field must transition to confirmed with confidence ≥ 0.90, otherwise remain needs confirmation with reason captured
Quiet Hours and Carrier/Platform Throttling Compliance
Given firm-configured quiet hours (default 21:00–08:00 recipient local time) When the system would send a proactive prompt during quiet hours Then it must defer the prompt until quiet hours end unless the contact sends an inbound message during quiet hours, in which case a single contextual reply is permitted And the system must limit proactive prompts to a maximum of 3 per 24 hours per contact with a minimum spacing of 10 minutes between prompts And if the contact sends STOP/UNSUBSCRIBE (SMS) or opts out via platform controls, the system must cease all outbound prompts within 5 seconds and record opt-out status with timestamp And HELP requests must receive the configured compliance reply within 5 seconds
Multilingual Prompting and Preference Handling
Given the contact’s language preference is known or can be inferred from recent messages When generating a prompt Then the prompt must be sent in the preferred or detected language if detection confidence ≥ 0.80, otherwise default to the firm’s primary language And the selected template must correctly render localized variables (e.g., date/number formats) for that language And an agent must be able to override the language for the conversation, after which subsequent prompts use the override And the system must store the language used per prompt and surface it in the audit log
Ambiguity Persistence and Human Escalation
Given a field remains in needs confirmation after two unsuccessful prompt attempts or has confidence < 0.60 after parsing the latest reply When ambiguity persists Then the system must create a human escalation task with a summary of unresolved fields, last candidate values, confidence scores, and relevant message excerpts And it must notify the assigned responder via the configured channel within 1 minute And upon responder acknowledgment, automated prompting for those fields must pause until manually resumed or resolved And the system must record escalation start time, assignee, and resolution outcome
Cross-Session Resume Logic
Given an intake conversation becomes inactive for ≥ 30 minutes or the channel session is re-established later When the contact resumes messaging Then the system must restore the last-known checklist state and continue prompting only for fields with status missing or needs confirmation, without re-asking confirmed information And conversation state must persist for at least 30 days from last activity And field histories must be merged across sessions with a single authoritative value per field and full audit trail
Outstanding Fields Checklist UI for Responders
Given a mapped intake exists with unresolved fields When a responder opens the intake in the CaseSpark UI Then a checklist must display outstanding fields categorized by status (missing, inferred, needs confirmation) with real-time updates within 2 seconds of new messages And selecting a field must reveal its current candidate value, source message link, confidence score, and last prompt sent And the responder must be able to confirm, edit, or mark not applicable for any field with a required reason, and all actions must be logged with user, timestamp, and prior value
Review & Correction Workbench
"As an after-hours responder, I want a simple review screen to verify and correct extracted fields so that I can confidently finalize an intake in minutes."
Description

Provide a side-by-side review UI showing the chat thread and the extracted field values with confidence indicators. Allow accept/reject, quick edits, and inline corrections that propagate back to the structured record. Highlight the exact message snippets that support each field, track changes for audit, and offer keyboard shortcuts for rapid triage. Enable one-click commit to matter creation, conflict screening, and document assembly once required fields meet thresholds. Optimize for mobile so responders can finalize intakes on the go.

Acceptance Criteria
Side-by-Side Review with Confidence and Snippet Highlighting
Given a ThreadMapper extraction with identified fields, mapped snippets, and confidence scores for a chat thread up to 200 messages When the responder opens the Review & Correction Workbench Then the chat thread renders on the left and the extracted fields panel on the right without overlap within 2s on desktop and 3s on mobile 4G And each extracted field displays a numeric confidence score (0–100%) with a visual confidence indicator And selecting or hovering a field scrolls the chat to the first supporting snippet and highlights all supporting snippet(s) until deselected And clicking a highlighted snippet focuses the corresponding field in the fields panel And any field lacking a mapped snippet is flagged “No evidence” and cannot be auto‑accepted
Inline Accept/Reject and Quick Edits Propagate to Structured Record
Given a field with one or more candidate values When the user Accepts the current value (via click or shortcut) Then the field status becomes Accepted, the value is persisted to the structured intake record within 500 ms, and the field is excluded from further auto‑suggestions Given a field with multiple candidates When the user Rejects the current value Then the rejected value is removed, the next best candidate (by confidence) is surfaced, and the structured record remains unset until acceptance Given the user performs a Quick Edit inline When the edit is confirmed Then normalization rules apply (dates -> ISO‑8601, names -> proper case, addresses -> standardized), the change persists within 500 ms, and dependent fields recalculate And after any accept/reject/edit action, completeness and missing‑field counts update within 500 ms and confidence thresholds are re‑evaluated And an auto‑save indicator shows Saved within 1s of the action
Keyboard Shortcuts for Rapid Triage
Given the workbench has input focus When the user presses A Then the current field is accepted When the user presses R Then the current field is rejected (or next candidate is surfaced if available) When the user presses E Then inline edit opens and the field input is focused When the user presses J or K Then navigation moves to the next/previous incomplete field respectively When the user presses Cmd/Ctrl+Enter Then Commit executes if enabled, else a tooltip explains unmet requirements When the user presses ? Then a shortcuts overlay appears listing all keys and is dismissible with Esc And all shortcut actions perform identically to their click/touch equivalents and are recorded in the audit trail
Comprehensive Audit Trail of Corrections
Given any accept, reject, edit, or commit action Then an immutable audit entry is created capturing user ID, UTC timestamp, field name, prior value, new value, action type, supporting snippet IDs, and intake/matter context And the user can view a per‑intake audit timeline, filter by field/action, and copy/export the log as JSON And the user can revert the last change for a field, creating a new audit entry with the reversal And audit data persists for at least 7 years and is retrievable within 2s for an intake with up to 500 actions
Threshold‑Gated One‑Click Commit to Matter, Conflict Screen, and Document Assembly
Given the intake template specifies required fields And each required field is present and either Accepted or has confidence ≥ 0.85 When the user clicks Commit Then the Commit button is enabled and triggers: (1) CaseSpark matter creation, (2) conflict screening, and (3) jurisdiction‑aware document assembly And a progress modal displays each step status (Pending/Success/Failed) in real time, with total processing completing within 15s for standard matters And on complete Success, links to the new matter, conflict report, and generated documents are shown, and the intake is marked Committed and becomes read‑only And on any failure, a clear error with remediation is displayed, partial successes are rolled back or flagged for retry, and Commit remains available And an operational log is stored capturing runtime, step results, and IDs for traceability
Mobile‑Optimized Review & Finalization
Given a device width between 320 px and 428 px on a 4G network (~10 Mbps down, ~50 ms RTT) When the workbench loads Then First Contentful Paint < 2.5s and Time to Interactive < 3.5s And the layout adapts to a stacked/toggle view with no horizontal scrolling; primary actions are reachable within 60 px of the bottom edge; tap targets ≥ 44×44 px; text scales with system settings And swipe left/right navigates next/previous field; long‑press opens context actions; the virtual keyboard never obscures the active input And if the network is offline/flaky, Save Draft appears and auto‑save retries up to 3 times with exponential backoff And all desktop capabilities (accept/reject/edit, snippet jump, commit) are available on mobile; external keyboards support the same shortcuts
Consent, Privacy, and Compliance Safeguards
"As a firm owner, I want consent and privacy controls baked into messaging so that we stay compliant and protect client confidentiality without extra work."
Description

Capture and record explicit consent for SMS/WhatsApp communications, display firm-configurable disclaimers, and honor opt-out requests automatically. Encrypt messages at rest and in transit, restrict access by role, and redact sensitive PII from notifications. Apply retention policies to threads, log all system decisions (prompts sent, fields inferred), and maintain an immutable audit trail tied to the matter. Ensure carrier and platform policy adherence to minimize delivery risk and protect client confidentiality.

Acceptance Criteria
Consent and Disclaimers Capture & Versioning
Given an inbound SMS or WhatsApp message from an unknown contact, When ThreadMapper sends the first automated reply, Then the message includes firm-configured disclaimer text and an explicit consent request. Given no prior consent is recorded for the contact and channel, When any non-consent outbound message would be sent, Then the system blocks it and only allows a consent-request message until consent is captured. Given the client provides explicit consent (e.g., YES, I AGREE, WhatsApp CTA), When the consent is received, Then the system records timestamp, channel, thread ID, disclaimer version ID, jurisdiction applied, and actor (automated or user) tied to the matter. Given firm administrators publish a new disclaimer version, When new conversations begin, Then the new version is presented and the accepted version ID is stored with the consent record. Given the matter’s jurisdiction or the contact’s country code requires specialized language, When the first automated reply is sent, Then the system selects the jurisdiction-appropriate disclaimer template. Given no consent is obtained within 24 hours of first contact, When further automation would occur, Then the system limits replies to a periodic consent reminder and flags the conversation for human review.
Automated Opt‑Out Handling and Global Suppression
Given a client sends an opt-out keyword (STOP, STOPALL, UNSUBSCRIBE, CANCEL, END, QUIT) via SMS or blocks the business on WhatsApp, When the message/event is received, Then all outbound messages to that contact on that channel cease immediately and a single opt-out confirmation is sent where permitted. Given a contact or WhatsApp ID is in an opted-out state, When any user attempts to send a message from any matter, Then the system blocks the send, surfaces the suppression reason, and requires fresh explicit re-consent to re-enable. Given opt-out keywords are received in varying case or with surrounding punctuation, When processed, Then detection is case-insensitive with word-boundary matching. Given the contact later sends a recognized opt-in keyword (START, UNSTOP, YES) or explicit re-consent, When received, Then the system records new consent and removes the global suppression entry. Given an opt-out event occurs, When audit data is generated, Then the event is recorded with timestamp, channel, matter linkage, user/system actor, and previous consent state.
End‑to‑End Encryption and Key Management
Given any message content or attachment ingested by ThreadMapper, When stored at rest, Then it is encrypted with AES‑256 and encryption keys are rotated at least every 180 days. Given data is transmitted between CaseSpark services and messaging providers, When messages are sent or received, Then TLS 1.2+ is enforced end‑to‑end. Given backups or search indexes containing message content are generated, When persisted, Then they are encrypted under the same key management policies as primary storage. Given a non-authorized principal attempts to access decryption keys, When the attempt occurs, Then access is denied and the event is logged with principal, time, and resource. Given a simulated key revocation/rotation event, When decryption of old data is attempted, Then only principals with explicit decrypt permission and valid key versions can read, and all access is logged.
Role‑Based Access Controls and PII Redaction in Notifications
Given users have roles (Admin, Attorney, Intake Specialist, After‑Hours Responder), When viewing message threads, Then only roles with the ViewSensitivePII permission can see full PII; others see masked values according to policy. Given a notification (email, push, chat) is generated from a message containing sensitive PII (e.g., SSN, DOB, driver’s license, passport, bank/credit numbers, full street address), When the notification is sent, Then the PII is redacted using defined mask rules (e.g., last4 only, YYYY‑**‑**, partial address) and a redaction banner is included. Given a user without sufficient permissions attempts to access a redacted value, When they click to reveal, Then access is blocked and the attempt is recorded in the audit log. Given an administrator updates mask rules or role permissions, When changes are saved, Then they take effect immediately for new notifications and next page view, and the change is captured in the audit trail.
Retention Policies and Legal Holds for Threads
Given an administrator configures retention rules by matter type, jurisdiction, and channel, When the policy is enabled, Then threads and attachments older than the configured age are auto‑archived or purged per rule on a scheduled job. Given a matter is converted to an engagement, When calculating retention, Then the retention clock is based on matter closure date or last activity, whichever is later, unless overridden by policy. Given a legal hold is placed on a contact, thread, or matter, When the retention job runs, Then items under hold are excluded from purge until the hold is released, and this exception is logged. Given content is purged by retention policy, When the purge completes, Then content is securely deleted, while minimal metadata (IDs, timestamps, hash) remains in the immutable audit trail for proof of deletion. Given an export is requested prior to purge, When executed, Then the system produces a complete export of thread content and audit records within the SLA window and logs the export event.
Immutable Audit Trail of Prompts, Inferences, and Actions
Given ThreadMapper generates prompts and maps inferred values to intake fields, When an inference occurs, Then the system logs the source snippet, inferred field, confidence score, model/version ID, and whether a user accepted/edited/rejected with timestamps. Given any configuration change (disclaimer updates, retention policies, role/permission changes), When saved, Then the audit trail records who, what, when, previous value, and new value. Given audit records are stored, When persisted, Then they are append‑only and hash‑chained (SHA‑256) per matter to detect tampering, with a verifiable digest available. Given an auditor requests the trail for a matter, When exported, Then the system returns a complete, ordered, read‑only audit file including verification data within 60 seconds for matters under 10k events.
Carrier/Platform Compliance and Delivery Risk Controls
Given the first SMS message to a new contact is sent, When composed by the system, Then it includes the firm’s identity and required compliance language (HELP/STOP instructions and “Msg&Data rates may apply”). Given a business‑initiated WhatsApp conversation is started, When sending the first message, Then a pre‑approved WhatsApp template is used and the template name, language, and category are logged. Given repeated carrier/platform error codes indicating filtering or quality issues are returned, When thresholds are met, Then the system throttles/queues traffic, alerts administrators, quarantines the sender ID if needed, and logs remediation steps. Given 10DLC/brand registration or WhatsApp verification is incomplete, When an outbound campaign is attempted, Then the system blocks the send and surfaces a setup checklist and error reason to the user. Given outbound volume approaches rate limits, When thresholds are exceeded, Then adaptive backoff and rate limiting are applied to minimize filtering risk while ensuring delivery where possible.
Engagement Handoff to E‑Sign & Filing
"As an attorney, I want completed chat intakes to flow straight into e-sign-ready documents so that I can move from first contact to engagement and filing without delays."
Description

When an intake reaches completeness criteria, auto-assemble jurisdiction-aware engagement letters and initial filings with prefilled data and prepare them for e-sign. Choose the client’s preferred channel for delivery (SMS/WhatsApp link or email), track signature and document status, and update the matter automatically. Trigger conflict checks and document assembly workflows in CaseSpark with mapped fields, reducing time from chat to engagement and filing.

Acceptance Criteria
Auto-Assembly on Intake Completeness
Given an intake has a status of Complete with required matter type and jurisdiction resolved When the engagement handoff is initiated Then the system assembles the jurisdiction-appropriate engagement letter and initial filing documents within 30 seconds And all mandatory fields are prefilled from mapped intake data with no unresolved placeholders And a generation event with document IDs and template version is logged with a timestamp Given an intake is Not Complete When the engagement handoff is attempted Then assembly is blocked and the UI lists each missing field by label and section
Jurisdiction Detection and Template Selection
Given client location, court selection (if captured), and matter type are present When document assembly runs Then the system determines jurisdiction using configured priority rules (explicit court > county > zip/postcode > state) And selects the correct template set for that jurisdiction and matter type And records the template set name and version in the matter history And if multiple jurisdictions are possible, the user is prompted to select one before proceeding
Field Mapping and Normalization
Given intake fields mapped from ThreadMapper (parties, dates, addresses, contact info) When documents are generated Then 100% of mandatory one-to-one mapped fields are inserted without transformation errors And dates are normalized to the jurisdiction-required format And addresses pass validation (street, city, state/province, postal code) or are flagged for correction prior to send And phone numbers are formatted to E.164 in the documents where applicable And no placeholder tokens remain in the final PDFs
Preferred Channel Delivery and Fallback
Given the client’s preferred delivery channel is captured as SMS, WhatsApp, or Email and a valid destination exists When documents are prepared for e-sign Then a secure signing link is sent via the preferred channel within 60 seconds of assembly And delivery status (Queued, Sent, Delivered, Failed) is recorded with provider event timestamps And if SMS/WhatsApp delivery fails within 5 minutes and an email address is on file, a fallback email with the link is sent automatically and logged And a single consolidated activity entry is written to the matter timeline
E-Sign Flow and Signature Tracking
Given documents have been sent for signature When the recipient opens the link Then the document status updates to Opened with timestamp When the recipient completes all required signature fields Then the status updates to Signed and the executed PDF with audit trail is stored in the matter And the signer’s IP, user agent, and timestamps are captured in the audit trail And if not signed within 48 hours, up to 2 reminders are sent at 24-hour intervals and logged And users can manually resend the signing link from the matter
Conflict Check Trigger and Enforcement
Given mapped parties (client, opposing party, related parties) exist from the intake When the engagement handoff is initiated Then an automatic conflict check runs using the mapped parties against the firm’s conflicts database And if a potential conflict is detected at Medium or High severity, sending for signature is blocked and a Conflict Review task is created and assigned And if Clear, the send proceeds And the conflict check results, timestamp, and reviewer (if applicable) are recorded in the matter
Matter Auto-Update and Filing Package Creation
Given the engagement documents are Signed When the signature event is received Then the matter status updates to Engaged within 2 minutes And the executed documents are attached to the matter with immutable file hashes And an initial filing package is assembled using the signed documents and jurisdiction-required metadata And if e-filing integration is configured, the package is submitted and filing receipt and envelope ID are stored; otherwise a File with Court task is created with due date per court SLA And all status changes are reflected on the matter timeline with timestamps

SnapFill OCR

Extracts names, DOBs, case numbers, and addresses from photos and screenshots (IDs, paystubs, court orders) and normalizes them into your matter fields. Built for smartphone images with instant validation and alias matching to existing contacts, cutting errors and saving minutes per intake.

Requirements

Smart Image Capture & Quality Assurance
"As an intake specialist, I want the app to fix and validate my photos automatically so that extracted fields are accurate the first time and I don’t have to chase clients for new pictures."
Description

Captures images from smartphone camera or file upload, automatically detects document edges, de-skews, de-rotates, reduces glare, and enhances contrast to maximize OCR accuracy. Supports JPEG, PNG, and PDF (single and multi-page), strips EXIF metadata, and compresses files without losing legible detail under a configurable size limit. Provides a real-time quality score and recapture prompts when blur, cutoff, or shadow risk extraction accuracy. Integrates with CaseSpark’s intake workflow so users can capture during a call and proceed directly to extraction without leaving the matter.

Acceptance Criteria
Auto Edge Detection, Crop, De-skew, and Rotation
Given a smartphone photo of a document with up to 20° skew and any rotation When the user captures or uploads the image Then edges are detected with IoU >= 0.95 vs ground truth on the QA set And background is auto-cropped with <= 2 px average margin error And the image is de-skewed to residual rotation <= 1° And the image is auto-rotated upright with >= 99% accuracy And a preview renders within 1000 ms P50 and 2000 ms P95 on mid-tier devices And Accept and Retake controls are displayed And if edge-detection confidence < 0.90, a recapture prompt with reason is shown
Real-time Quality Score and Recapture Prompts
Given an image preview after capture or upload When the quality analyzer runs Then a quality score (0–100) is displayed within 300 ms P95 And blur is flagged when variance of Laplacian < configured threshold And glare is flagged when specular highlights cover > 3% of document area And shadow is flagged when local contrast < configured threshold over > 5% of text regions And cutoff is flagged when > 1% of detected text boxes intersect the crop boundary And when any risk is detected, a targeted recapture tip text is displayed (such as 'Move to brighter area', 'Hold steady', 'Fill the frame')
Contrast Enhancement Without Detail Loss
Given a captured or uploaded image When enhancement (denoise, contrast, sharpening) is applied Then OCR character accuracy on the validation set improves by >= 5% relative or >= 2% absolute compared to the unenhanced image And no more than 1% of images experience an OCR accuracy decrease > 1% absolute And 8–10 pt text remains legible at 200% zoom on 20 sampled regions per image And visual artifacts do not exceed an SSIM drop of 0.03 relative to the pre-enhanced image And the user can toggle between Original and Enhanced in the preview
Format Support and Multi-page Processing
Given uploads of JPEG, PNG, and PDF files (single- and multi-page) When the files are processed Then all listed formats are accepted and processed without error And multi-page PDFs up to 50 pages are split and processed page-by-page in order And camera capture supports sequential capture of multiple pages into one set And each page receives crop/de-skew/enhance and an individual quality score And original page order is preserved into OCR extraction
Configurable Size Limit and Quality-Preserving Compression
Given a configured max file size per document set (default 5 MB, configurable 1–15 MB) When processed images are saved for OCR Then outputs meet the size limit while maintaining SSIM >= 0.95 versus the enhanced originals And OCR character accuracy on a 50-image sample does not drop by > 1% absolute due to compression And if the size limit cannot be met without violating the quality floor, the system prompts the user to increase the limit or recapture at higher quality and does not silently degrade And compression completes within 500 ms P95 per page on mid-tier devices
EXIF and Embedded Metadata Removal
Given images captured via in-app camera or uploaded files When the system stores or transmits the processed assets Then all EXIF metadata (including GPS, device model, serial, orientation, and timestamps) are stripped from output images And generated PDFs contain no XMP metadata or embedded EXIF from source images And an automated verification scan finds zero EXIF/XMP keys in saved assets
Seamless Intake Workflow Handoff to Extraction
Given a user in an active CaseSpark intake matter during a call When they capture or upload documents and tap Proceed Then the user remains in the same matter context (no page-level navigation away) And the processed pages are passed automatically to SnapFill OCR extraction And the extraction screen becomes ready within 2000 ms P95 after acceptance And the user can continue the intake flow without re-entering client or matter identifiers
Document Type Auto-Classification
"As a solo attorney, I want the system to recognize the kind of document I uploaded so that it extracts the right fields without me configuring anything."
Description

Automatically classifies uploaded images as government ID, paystub, court order, utility bill, or other supported categories using a lightweight model, returning a confidence score. Routes each class to a tailored extraction pipeline and template, with a manual override when confidence is low. Maintains a versioned label set and provides telemetry to continuously improve classification performance. Exposes the selected type to downstream validation and audit logs within CaseSpark.

Acceptance Criteria
High-Confidence Auto-Classification and Routing
Given an uploaded image of a supported document category and the classifier returns confidence >= 0.80 (default threshold), When classification completes, Then the system assigns the predicted document type and routes the image to the corresponding category-specific extraction pipeline and template without user intervention. And the classification response includes documentType, confidence (0.00–1.00), modelVersion, and labelSetVersion. And the classification event is recorded with selectionSource = "auto".
Low-Confidence Manual Override Flow
Given an uploaded image whose top prediction confidence < configured threshold, When the user is prompted to choose a document type, Then the system blocks auto-routing until a type is selected. When the user selects a type and confirms, Then the system routes using the selected type and logs originalPredictionType, originalConfidence, finalType, userId, and timestamp. And selectionSource = "manual" is recorded and visible in audit logs. When the user cancels, Then the document remains in status "Awaiting Type" and no extraction pipeline is invoked. And the confidence threshold is configurable per organization and defaults to 0.80.
Confidence and Selected Type Exposed to Downstream Validation and Audit Logs
Given a document has a finalized selectedType (auto or manual), When downstream validation is executed, Then validators receive selectedType and confidence in the payload and can branch rules accordingly. And an audit log entry includes documentId, selectedType, confidence, selectionSource, modelVersion, labelSetVersion, and timestamp. When the audit log is queried by documentId, Then the most recent classification record is returned within 1 second.
Versioned Label Set and Model Version Tagging
Given activeLabelSetVersion = vN and modelVersion = M, When a document is classified, Then the result stores labelSetVersion = vN and modelVersion = M with the prediction. When the label set is updated to vN+1, Then subsequent classifications store labelSetVersion = vN+1 while prior records retain vN unchanged. When a classification references an unknown labelSetVersion, Then the system rejects it and logs an error. When requested via the metadata endpoint, Then the system returns the active label set and version identifier.
Unsupported or Ambiguous Document Handling ('Other' Fallback)
Given the top predicted label is "Other" with confidence >= configured threshold, When classification completes, Then the system assigns "Other" and routes to the generic extraction pipeline and template automatically. Given the top predicted label is any category with confidence < configured threshold, When classification completes, Then the system does not auto-assign a type and triggers the manual override prompt. And the "Other" option is available in the manual selection list.
Telemetry Capture for Continuous Improvement
Given any classification outcome (auto or manual), When the classification record is persisted, Then telemetry captures predictedType, confidence, finalType, selectionSource, modelVersion, labelSetVersion, and event timestamp. And telemetry includes no image binary content. When telemetry is aggregated daily, Then the system can produce per-class accuracy, top-1 accuracy, and confusion counts for the last 30 days. And telemetry records can be exported as CSV or via an internal API.
Classification Latency and Throughput Targets
Given up to 10 smartphone images (<= 12MP, JPEG/PNG) are uploaded concurrently, When classification runs on the standard server configuration, Then p95 classification latency per image <= 300 ms and p99 <= 500 ms. And throughput is >= 20 images/second sustained for at least 60 seconds. And no more than 0.1% of classifications time out (10s timeout), with timed-out items retried once and logged.
Field Extraction & Normalization Engine
"As a paralegal, I want names, DOBs, addresses, and case numbers pulled into the matter automatically so that I can move from intake to filing without manual retyping."
Description

Performs OCR and structured entity extraction for full legal names (including middle names and suffixes), dates of birth, case numbers, addresses, and other identifiers from supported documents. Consolidates values across pages, removes duplicates, and outputs per-field confidence scores. Normalizes values to system standards (ISO-8601 dates, USPS-verified addresses, jurisdiction-specific case number canonicalization) and maps them into CaseSpark matter fields. Exposes a field-by-field review screen with inline image snippets for quick verification before save.

Acceptance Criteria
OCR from Smartphone Image of Government ID
Given a smartphone photo (8–12 MP) of a state driver’s license with up to 15° rotation and minor glare When the Field Extraction & Normalization Engine processes the image Then it extracts Full Legal Name, Date of Birth, and Address into discrete matter fields And returns per-field confidence scores (Name and DOB ≥ 0.90; Address ≥ 0.85) And includes source bounding-box coordinates for each extracted field And completes processing within 3 seconds on a standard server profile
Multi-Page Document Consolidation and De-duplication
Given multiple images/pages of the same document set containing overlapping personal data (e.g., paystub + court order) When processing is completed Then the engine consolidates identical fields across pages and removes duplicates And selects the highest-confidence non-conflicting value per field And retains a provenance list of page/image IDs and regions contributing to each field And flags any conflicting values within 0.05 confidence of each other as Needs Review
Name Parsing with Middle Names and Suffixes
Given a full legal name string containing middle names/initials and suffixes (e.g., "ALVAREZ, MARÍA LUISA III", "Dr. John Q. Public Jr.") When the engine parses the string Then it outputs FirstName, MiddleName, LastName, and Suffix in separate fields with diacritics preserved And strips honorifics (e.g., Dr., Mr., Ms.) from the parsed fields And normalizes suffix to a controlled vocabulary (e.g., Jr, Sr, II, III) while retaining the original in rawValue And achieves a confidence score ≥ 0.90 for First, Last, and Suffix; ≥ 0.80 for Middle And stores any detected aliases as additional names without overwriting the primary name
DOB Normalization to ISO-8601
Given a Date of Birth in varying formats (MM/DD/YY, DD-MM-YYYY, "Jan 5, 79") When normalization is performed Then the DOB is validated as a real calendar date (including leap-year rules) And normalized to ISO-8601 format (YYYY-MM-DD) with century disambiguation using a configurable cutoffYear (default 24) And the original text is stored as rawValue And confidence ≥ 0.95; otherwise the field is marked Needs Review and is not auto-saved
USPS Address Verification and Normalization
Given a U.S. mailing address extracted from a photo with common abbreviations and minor OCR noise When address parsing and verification are executed Then the address is canonicalized to USPS Publication 28 format (street, city, state, ZIP+4 when available) And deliverability is validated via CASS/DPV with DPV status returned And secondary unit designators (e.g., Apt, Ste) are normalized and not lost And if USPS verification fails, the parsed components are retained and the field is flagged Needs Review And for non-U.S. addresses, country-specific normalization is applied and USPS checks are skipped
Jurisdiction-Specific Case Number Canonicalization
Given a case number string for a known jurisdiction with varied punctuation/spacing (e.g., "22 FL 012345", "2023-DC-01234") When the jurisdiction is provided by context or reliably extracted from the document Then the number is transformed to the canonical format for that jurisdiction And pattern rules (e.g., prefixes, year length, check digits) are validated with a pass/fail result And the original string is stored as rawValue alongside the canonical value And confidence ≥ 0.90; if jurisdiction cannot be determined, the user is prompted to select one before canonicalization
Field Review Screen with Inline Snippets and Save Mapping
Given extracted fields pending user verification When the review screen loads Then each field displays the value, confidence percentage, and a clickable image snippet highlighting its source region And the user can Accept, Edit, or Reject each field inline And "Accept All" auto-selects fields with confidence ≥ the org-defined threshold (default 0.90) And on Save, accepted values map atomically into the correct CaseSpark matter fields with an audit log (user, timestamp, source) And validation errors are shown inline; unsaved changes trigger a navigation warning And UI performance budgets are met (≤200 ms per-field render; <1 s commit to save)
Jurisdiction-Aware Validation Rules
"As a two-attorney practice owner, I want extracted data checked against my court’s formats so that filings don’t get rejected and I avoid rework."
Description

Validates extracted fields against configurable, jurisdiction-specific rules, including court case number formats, address locality constraints, and date plausibility checks. Highlights invalid or low-confidence fields directly on the image overlay and suggests corrections or alternative parses. Supports hard stops for critical errors and soft warnings for non-blocking issues, with override and reason capture. Ships with a rules library for common family-law jurisdictions and an admin UI to update rules without code.

Acceptance Criteria
Case Number Format Validation by Jurisdiction
Given active jurisdiction "DemoCounty-FL" and a published rule R-CASE-FMT with pattern "FL-[0-9]{6}-FAM" and severity "critical" When the OCR extracts case_number "FL-123456-FAM" Then the case_number field is marked Valid and no error or warning is shown Given the same rule When the OCR extracts case_number "123-ABC" Then the case_number field is marked Invalid with error_code "format_mismatch", the image overlay highlights the field in red, and Save/Submit actions are blocked Given the same rule and an alternative parse candidate "FL-123456-FAM" When the user clicks "Apply suggestion" Then the case_number field updates to the suggested value and re-validates to Valid
Address Locality Constraint Enforcement
Given active jurisdiction "Travis County, TX" and published rules R-ADDR-LOCALITY requiring ZIP ↔ city ↔ county ↔ state consistency with the reference dataset and severity "warning" When the OCR extracts address {street:"500 W 2nd St", city:"Austin", state:"TX", zip:"78701"} Then the address field passes locality validation with no warnings Given the same rules When the OCR extracts address {street:"500 W 2nd St", city:"Austin", state:"CA", zip:"78701"} Then a warning with code "locality_mismatch" is shown, the field is highlighted in yellow, and Save/Submit remains enabled Given the warning is shown When the user chooses "Override" Then the system requires an override reason 20–500 characters, captures user id, timestamp, and reason, and logs audit_event "override_locality_mismatch"
Date Plausibility Checks on Extracted Dates
Given published rules R-DATE-PLAUS defining that DOB must be <= today and >= 1900-01-01 and that filing_date must be within ±30 days of intake_created_at and severity "critical" for DOB and "warning" for filing_date When OCR extracts DOB "2030-05-01" Then the DOB field is marked Invalid with error_code "date_in_future", highlighted red, and Save/Submit is blocked Given the same rules When OCR extracts filing_date "180 days ago" relative to intake_created_at Then a warning with code "filing_date_out_of_range" is shown, highlighted yellow, and Save/Submit remains enabled Given ambiguous date input "03/04/05" When rule R-DATE-PLAUS provides alternative parses ["2005-03-04","2005-04-03"] Then the UI displays both ISO-formatted suggestions and selecting one updates the field and clears the warning if valid
On-Image Overlay Highlighting with Correction Suggestions
Given any invalid field with a known bounding box and rule-provided message and suggestions When validation runs immediately after OCR extraction Then the overlay renders a bounding box with color red for errors and yellow for warnings within 300 ms, shows the message on tap/click, and lists up to 3 ranked suggestions Given the user accepts a suggestion from the overlay When the value updates Then the overlay state updates to green within 300 ms and the detail panel shows "Validated" with the applied rule id Given a low-confidence extraction below the configurable threshold (default 0.85) When no rule is violated Then the overlay shows a yellow "low_confidence" indicator and allows manual edit without blocking
Hard Stops vs Soft Warnings with Override and Reason Capture
Given a rule with severity "critical" When the rule fails during intake validation Then Save and Submit actions are disabled, the error banner states the blocking rule id and reason, and the "Override" control is not available Given a rule with severity "warning" When the rule fails Then Save and Submit actions remain enabled and an "Override" control is available Given the user selects "Override" for a warning When they enter a reason between 20 and 500 characters and confirm Then the override is recorded with user id, timestamp, rule id, original value, new value (if any), and reason, and an audit record is persisted
Admin UI Rule Management and Versioning
Given an Admin role user When they create a new rule for jurisdiction "Harris County, TX" with id "R-CASE-FMT-HCTX", pattern, severity, and test cases, and click Publish Then the rule is versioned at v1, appears as Published in the rules list, passes its inline test cases, and is applied to new validations within 1 minute Given an existing rule at v1 When the admin edits and publishes changes Then a new version v2 is created, v1 remains immutable and available for rollback, and all new validations use v2 while existing open intakes can be revalidated on demand Given a misconfiguration When the admin clicks "Rollback to v1" Then v1 becomes the active version within 1 minute and a rollback audit entry is recorded
Preloaded Jurisdiction Rules Library Availability
Given a fresh tenant When an Admin opens Rules Library Then a preloaded library is available containing at least 20 rules across at least 6 family-law jurisdictions, each with name, description, default severity, and sample test cases Given the library view When the admin selects and enables "California Family Court" and "Texas Family Court" rule sets Then those rule sets are added to the tenant in Draft status for review and can be Published without code deployment Given library updates are released by CaseSpark When the admin clicks "Sync Library" Then new or updated rules are fetched and surfaced for opt-in without downtime, and no existing active rule version is altered until published by the admin
Contact Alias Match & De-duplication
"As an intake coordinator, I want the system to spot existing clients by aliases or past names so that I avoid duplicates and improve conflict screening."
Description

Compares extracted identities with existing contacts using fuzzy matching across names, known nicknames, prior surnames, DOB, phone, email, and address to detect likely matches and aliases. Presents ranked suggestions with confidence scores and differences, enabling one-click link or merge while preserving audit history. Adds confirmed variants to the contact’s alias list to improve future conflict checks and prevents duplicate contact creation in CaseSpark.

Acceptance Criteria
Ranked Match Suggestions with Confidence and Differences
Given extracted identity with name, DOB, phone, email, and address normalized from SnapFill OCR When contact matching is executed Then display up to 10 existing contact suggestions ordered by descending confidence score (0–100) And each suggestion shows a numeric confidence score, matched fields, and highlighted differences for non-matching fields And nickname and prior-surname matches are labeled And results render within 1.5 seconds of OCR completion And if no suggestion meets or exceeds the default match threshold (>= 80), show “No strong matches” and list the top 3 below-threshold candidates flagged as Low Confidence
One-Click Link to Existing Contact
Given a suggested existing contact is selected When the user clicks Link Then the intake record is associated to the selected contact without creating a new contact And any new name variants, emails, phones, or addresses from the intake not already on the contact are appended to the contact’s alias list And an audit entry is recorded with actor, timestamp, intake ID, contact ID, action=Link, and before/after alias list And the UI reflects Linked state and disables Create New Contact for this intake
One-Click Merge of Duplicate Contacts
Given a provisional new contact and a suggested existing contact are selected for merge When the user clicks Merge Then the system merges records in <= 2 seconds using field-precedence rules (prefer non-null most recently updated; union multi-value fields for phone/email/address) And all matters, tasks, notes, and conflict flags from the losing record are reassigned to the surviving contact And all name/phone/email/address variants are added to the surviving contact’s alias list And the losing contact ID is archived and redirected to the surviving contact And a complete audit trail is recorded with actor, timestamp, both IDs, field-level before/after values, and merge rationale (if provided)
Prevent Duplicate Contact Creation on Save
Given the highest-ranked suggestion meets or exceeds the default match threshold (>= 80) When the user attempts to create a new contact Then the system blocks creation and displays a modal with the top suggestions and confidence scores And the user may override only after entering a justification of at least 10 characters and having the Duplicate Override permission And any override or link action is logged in audit with actor, timestamp, and justification And no duplicate contact is created when Link is chosen
Nickname and Prior Surname Recognition
Given first-name variants that are known nicknames (e.g., Robert↔Bob, William↔Bill, Margaret↔Maggie, Elizabeth↔Liz, Katherine↔Kate) When matching is executed Then nickname equivalence contributes as an exact first-name match for scoring and is labeled Nickname Match in the suggestion And last-name matches against a stored prior surname or hyphenated component contribute as a last-name match and are labeled Prior Surname Match And upon Link or Merge, any encountered variants are stored on the contact’s alias list with type (Nickname, Prior Surname)
Alias-Driven Future Conflict Checks
Given a contact has aliases added via Link or Merge When a future conflict check is run using any alias variant from a new intake Then the conflict screening returns the aliased contact in < 1 second And the conflict result indicates which alias triggered the match And the alias list remains versioned and visible in audit history
Partial Data Tolerance and Normalization Safeguards
Given only partial identifiers are available (e.g., name + DOB, or email + phone) When matching is executed Then normalization is applied (phone to E.164, email lowercased/trimmed, address standardized to USPS/CASS where applicable) And suggestions still appear with appropriately reduced confidence and field-level difference highlights And with only a single identifier present, no suggestion will meet the default auto-block threshold (>= 80) And on the provided test dataset, the default threshold (>= 80) yields precision >= 95% for suggested matches and recall >= 85%
Secure Processing & Audit Trail
"As a managing attorney, I want secure handling and complete audit logs of document processing so that we meet compliance obligations and can trace any data change."
Description

Protects sensitive documents and extracted PII with encryption in transit and at rest, temporary storage with configurable retention, and role-based access controls. Optionally performs pre-processing on-device or in-region to minimize data exposure. Records an immutable audit trail of uploads, classifications, extractions, validations, user overrides, and merges, including timestamps and actor IDs. Provides admin access to export audit logs for compliance and supports redaction of non-required fields before saving to the matter.

Acceptance Criteria
Encrypt PII in Transit and At Rest
Given the SnapFill API endpoint, When a client uploads a document or extracted data, Then the connection must enforce TLS 1.2+ and reject TLS 1.1 or lower with a 4xx error. Given data is stored temporarily or persisted, When written to storage, Then it must be encrypted at rest using AES-256 or stronger with keys managed by the platform KMS. Given encryption keys are in use, When 90 days elapse, Then keys must be rotated automatically and old keys retired per policy without data loss. Given an auditor inspects the system, When checking cipher suites and storage configuration, Then evidence of TLS 1.2+ enforcement and at-rest encryption must be present in configuration and test results.
Configurable Temporary Storage Retention and Auto-Purge
Given an organization retention policy, When an admin sets temporary storage retention between 1 and 30 days (default 7), Then the system must persist that value at the tenant level. Given a document was uploaded to temporary storage, When its retention period elapses, Then the object and derived intermediates must be purged within 60 minutes and become irretrievable (404/410) via API and storage. Given purge completes, When audit logs are queried, Then a purge event with timestamp, object ID, and actor “system” must be present. Given retention is changed by an admin, When saving the setting, Then the change must be logged with previous value, new value, actor ID, and timestamp.
Role-Based Access Control for SnapFill Sources and Extracted PII
Given role permissions are configured, When a user without PII.View attempts to view or download source images or extracted PII, Then the request must be denied with 403 and logged. Given a user with PII.View and Matter.Edit, When accessing SnapFill results for a matter they are assigned to, Then access is granted and actions are logged with actor ID and timestamp. Given a user is not assigned to a matter, When they attempt access, Then access is denied regardless of role and the attempt is logged. Given an admin updates role permissions, When the change is saved, Then the change is recorded in the audit trail with old/new permissions and actor ID.
On-Device/In-Region Pre-Processing Option
Given the tenant has enabled On-Device Pre-Processing, When a supported mobile client captures an image, Then OCR pre-processing occurs on-device and only normalized text fields are sent to the server. Given the tenant has set Data Locality = EU, When server-side processing is required, Then all processing calls must resolve to EU-hosted endpoints and no traffic may leave the region. Given on-device capability is unavailable, When capture is attempted, Then the user is prompted to fall back to server-side processing only if policy allows; otherwise capture is blocked and logged. Given network inspection, When analyzing requests during processing, Then no image bytes are transmitted off-device for on-device enabled flows and all server calls terminate in the configured region.
Immutable Audit Trail for SnapFill Processing
Given SnapFill processes a document, When events occur (upload, classification, extraction, validation, user override, merge), Then each event must be recorded with event type, matter ID, document ID, actor ID, and ISO 8601 UTC timestamp. Given an event is written, When stored, Then the log must include a SHA-256 hash and previous-hash to form a tamper-evident chain. Given an attempt to alter or delete an event, When performed, Then the system must prevent mutation; any correction must be appended as a new event referencing the prior event. Given an integrity audit, When recomputing the hash chain over a date range, Then all events verify without gaps or hash mismatches.
Admin Export of Audit Logs for Compliance
Given an admin with Logs.Export permission, When they request an export by date range, matter ID, actor ID, and event types, Then the system generates a CSV or JSON export including all matching fields within 2 minutes for up to 100k events. Given an export is generated, When the file is delivered, Then it must include a cryptographic checksum (SHA-256) and metadata (exported at, filter criteria, tenant ID) and be downloadable for 7 days. Given an export request is too large, When it exceeds 100k events, Then the system must paginate or provide a continuation token without data loss. Given an export is downloaded, When verified with the checksum, Then the checksum must match and the audit trail entries must correspond to on-platform queries.
Redaction of Non-Required Fields Prior to Matter Save
Given extracted fields include non-required PII, When the user reviews results before saving, Then the UI must allow deselecting specific fields for redaction. Given fields are deselected, When saving to the matter, Then redacted fields must not be persisted, displayed, or included in downstream exports/search indexes. Given a redaction occurs, When auditing the matter, Then an audit event must record which fields were redacted (by field name only, not values), actor ID, and timestamp. Given a later re-extraction is performed, When it proposes previously redacted fields, Then the UI must require explicit user confirmation to save them and log the action.

DocSense

Auto‑detects document type on upload (e.g., driver’s license, marriage certificate, prior order) and routes only the needed data into the right sections. Auto‑redacts extra PII before it’s stored or shared, keeping Privacy‑First users comfortable while preserving everything required for filings.

Requirements

Document Type Auto-Detection
"As a solo family-law attorney, I want uploaded files to be auto-identified by type so that the right extraction and filing templates run without me sorting documents manually."
Description

Implement an on-upload classification engine that identifies common family-law document types (e.g., driver’s license, marriage certificate, prior orders, pay stubs) across PDFs and images (JPEG/PNG), including scanned and mobile-captured documents. Leverage OCR for image-based files, handle multi-page inputs, and support rotated/low-contrast images. Emit a document_type label and confidence score within 2 seconds for standard pages, and route to fallback manual selection when confidence is below threshold. Integrate with CaseSpark’s intake pipeline so the detected type determines the downstream extraction template, conflict-screening triggers, and assembly pathways.

Acceptance Criteria
Single-Page PDF Classification within SLA
Given a 1-page PDF of a standard driver’s license, When the user uploads it via CaseSpark intake, Then DocSense returns document_type "drivers_license" and confidence >= 0.95 within 2.0 seconds. And Then the API response includes document_type (string), confidence (0..1), pages (integer=1), processing_time_ms (<=2000). And Then the classification is saved to the intake record and visible in the upload details.
Image OCR with Rotation and Low Contrast
Given a rotated (90°) low-contrast but legible JPEG of a marriage certificate, When uploaded, Then DocSense normalizes orientation and performs OCR. And Then DocSense returns document_type "marriage_certificate" with confidence >= 0.85. And Then the response includes ocr_performed=true and orientation_correction_applied=true. And Then no manual intervention is requested when confidence >= configured_threshold.
Multi-Page Document Handling
Given a 4-page PDF of a prior court order, When uploaded, Then DocSense returns document_type "prior_order" with confidence >= 0.90 and pages=4. And Then one document-level label is applied to the entire upload and is consistent across pages. And Then processing completes without errors.
Confidence Threshold and Manual Fallback
Given any upload whose highest classification confidence < configured_threshold, When processed, Then DocSense sets needs_manual_selection=true and does not route to extraction, conflict screening, or assembly. And Then the user is prompted to select a document type from the supported list. And Then upon user selection, DocSense persists the chosen document_type, marks source="manual", sets confidence to null, and resumes downstream routing. And Then an audit log entry records the model’s top-3 predictions with scores and the user’s selection.
Pipeline Routing and Template Selection
Given a classified document with document_type "pay_stub" and confidence >= configured_threshold, When processing continues, Then the mapped extraction template for "pay_stub" is invoked and field extraction begins. And Then conflict screening is not triggered for "pay_stub". And Then the assembly pathway tag is set to "income_verification". And Then for document_type "drivers_license", conflict screening is triggered using extracted name and DOB, and the assembly pathway tag is set to "id_verification".
Supported Formats and Error Handling
Given an upload in a supported format (PDF, JPEG, PNG), When processed, Then DocSense attempts classification and emits document_type and confidence on success. And Then for uploads in unsupported formats, an error_code "unsupported_format" is returned and no document_type or confidence is persisted. And Then for corrupted or unreadable files, an error_code "unreadable_input" is returned and no document_type or confidence is emitted. And Then all errors are logged with a correlation_id and are visible in admin diagnostics.
Structured Data Extraction & Field Routing
"As an intake specialist, I want required data auto-filled into the correct sections so that I can move from call to filing without repetitive data entry."
Description

For each supported document type, extract only the required fields (e.g., full legal name, DOB, case number, court name, order date) using template- and ML-driven parsers and map them into CaseSpark’s canonical data model. Route extracted values to the correct intake workflow sections and prefill jurisdiction-aware document assembly fields. Support multi-entity extraction (petitioner/respondent), normalize values (dates, names), and de-duplicate against existing contacts to reduce conflicts and duplicates. Provide deterministic field provenance metadata for each mapped value to enable auditability and downstream validation.

Acceptance Criteria
Detect and Extract Required Fields from Marriage Certificate Upload
Given a clear scan or photo (≥200 DPI, ≤5 pages) of a US Marriage Certificate is uploaded to CaseSpark When DocSense processes the document Then the document type is classified as "Marriage Certificate" with confidence ≥ 0.95 And only the required fields are extracted: Party A full legal name, Party B full legal name, marriage date, issuing county/state, certificate/order number (if present) And each extracted value is mapped to the canonical model: person[].legal_name, person[].role=Spouse, marriage.marriage_date, jurisdiction.county, jurisdiction.state, document.certificate_number And the mapped values prefill Intake > Parties and Intake > Case Details > Marriage without creating duplicate entries And per-field confidence scores are stored; fields with confidence < 0.85 are flagged "Needs Review" and are not auto-committed And non-required PII (e.g., street address, witness names) is not persisted and is redacted in stored previews And end-to-end processing completes within 5 seconds at p95
Multi-Entity Extraction from Prior Court Order (Petitioner/Respondent)
Given a prior family-law court order (e.g., custody or divorce) from a supported jurisdiction is uploaded When DocSense processes the document Then parties and roles are extracted and mapped to person[].role values of "Petitioner" and "Respondent" (or jurisdictional equivalents) And multiple parties of the same role are supported and individually mapped And case_number, court_name, and order_date are extracted and mapped to case.case_number, court.name, and order.date And the values prefill Intake > Parties and Intake > Case Details > Existing Orders and the jurisdiction-aware document assembly fields And any role ambiguity (confidence < 0.85) flags the record "Needs Review" and highlights the source text on the relevant page And processing of a 1–10 page PDF completes within 8 seconds at p95
Jurisdiction-Aware Field Routing and Prefill
Given the matter jurisdiction is set to State=Texas, County=Travis, and a Driver’s License image is uploaded for the Petitioner When DocSense extracts DOB and residential address from the license Then those values route to the Petitioner entity and prefill Texas-specific fields in the Petition template bindings for Texas-Travis And if the jurisdiction is changed to State=California, County=Alameda after extraction, the system re-routes the same canonical values to California-specific bindings without duplicating party records And all downstream document-assembly field bindings reference the same canonical field IDs and provenance And no jurisdiction-inapplicable fields are populated
Value Normalization for Names and Dates
Given extracted name strings contain variations in case, whitespace, and suffixes (e.g., "SMITH, JOHN A. JR") and dates appear in formats such as "1/2/90" or "02 Jan 1990" When values are mapped to the canonical model Then names are normalized into components first_name="John", middle_name="A.", last_name="Smith", suffix="Jr" and full_legal_name="John A. Smith Jr" in Title Case And dates are normalized to ISO 8601 (YYYY-MM-DD); the example "1/2/90" is stored as "1990-01-02" using jurisdiction-configured century inference rules And whitespace is collapsed and diacritics preserved; the original raw text is retained in provenance.source_text
De-duplication Against Existing Contacts and Conflict Index Update
Given extracted party values map to a person with name and DOB that partially matches an existing contact in the firm database When the de-duplication engine evaluates the candidate Then if the match score ≥ 0.90, the extracted entity is auto-linked to the existing contact without creating a new record And if 0.70 ≤ match score < 0.90, the entity is created in a pending state and flagged for user confirmation showing both candidates And if match score < 0.70, a new contact is created And in all cases, the conflict index is updated and any match to an existing opposing party or restricted party triggers a conflict warning banner in intake within 1 second
Deterministic Field-Level Provenance Metadata for Mapped Values
Given any field is extracted and mapped to the canonical model When the record is saved Then a provenance object is stored for each mapped value with fields: document_id, page_number, bounding_box (x,y,w,h in pixels), source_text (≤200 chars), parser_strategy ("template"|"ml"), strategy_id, model_version, extraction_timestamp (UTC), confidence (0..1) And the provenance record is immutable and exposed via API GET /provenance/{field_id}; updates create a new version with active=true and prior versions set active=false And each downstream assembled document field includes a reference to the provenance_id that supplied its value And a UI "View Source" action highlights the exact bounding box on the original document
Privacy-First Auto-Redaction & PII Minimization
"As a privacy-conscious user, I want extra personal data removed automatically so that I can share documents with courts and clients without exposing unnecessary information."
Description

Before storage or share, automatically redact non-essential PII based on document type and jurisdictional filing requirements (e.g., truncate driver’s license numbers, mask SSNs, redact addresses not needed for filing). Apply redaction to both text and images (including barcodes/QRs), generate a redacted derivative for persistence and collaboration, and keep the original only ephemerally until extraction completes. Store only the minimum necessary data fields; drop or hash any extraneous PII. Maintain encryption in transit and at rest, and record redaction actions in an immutable log linked to each document version.

Acceptance Criteria
Jurisdiction-Aware SSN, ID, and Address Redaction on Upload
Given a user uploads a document containing SSNs, driver’s license numbers, and physical addresses and selects jurisdiction J When DocSense processes the upload Then SSNs are masked to last 4 digits, driver’s license numbers are truncated per J’s rule, and addresses not required for filing under J are fully redacted before any storage or sharing And Then the collaboration view, downloads, and API return only the redacted derivative; no unredacted PII is present in persisted storage And Then processing completes within 30 seconds for documents up to 25 pages
Barcode and QR Payload Suppression in Text and Images
Given a PDF or image contains barcodes or QR codes that may encode PII When DocSense processes the document Then all detected Code128, QR, PDF417, and Data Matrix codes are irreversibly redacted in the derivative and their payloads are not stored And Then each code region is 100% covered by the redaction box without leaking edges or quiet zones And Then detection achieves at least 95% recall on the standard test set while preserving document layout and text legibility
Redacted Derivative Creation and Ephemeral Original Purge
Given a document is uploaded for processing When text/field extraction completes successfully Then the system writes only the redacted derivative to persistent storage and purges the original and any intermediate caches within 60 seconds And When extraction fails Then the original is purged within 60 seconds and the document cannot be shared or exported And Then any attempt to access the original via UI or API returns 404 after purge
Data Minimization and Extraneous PII Hash/Drop
Given jurisdiction J’s filing schema is available When field mapping is applied during extraction Then only fields required by J are persisted in structured storage; all other PII fields are dropped or stored as a salted one-way hash And Then salted hashes cannot be reversed and are not used for filing or display And Then exports, backups, and analytics sinks include only the minimized dataset And Then an automated verification report lists all stored fields and confirms no extraneous raw PII persists
Immutable Redaction Audit Log per Document Version
Given a document undergoes redaction When redaction actions are executed Then an append-only audit record is created containing document version ID, timestamp, actor/process ID, applied rule-set and version, fields redacted, and cryptographic hashes of the original and derivative And Then the log is tamper-evident via chained hashing or WORM storage and is retrievable read-only by authorized roles And Then any attempt to modify or delete past entries is rejected and the attempt is logged
Encryption in Transit and at Rest Enforcement
Given any client or service interacts with documents or extracted data When requests are made to upload, view, download, or process Then TLS 1.2+ is enforced and plaintext HTTP is rejected with an error And Then all persisted artifacts (derivatives, extracted fields, logs containing PII, and backups) are encrypted at rest using KMS-managed keys with rotation policies enabled And Then configuration and audit evidence confirm encryption for object storage, databases, search indexes, and caches
Safe Fallback When Jurisdiction Rules Are Missing
Given the jurisdictional redaction rule-set is unavailable or times out When a document is uploaded Then a maximal redaction policy is applied and sharing/export is blocked until the correct rule-set is applied And Then the event is shown to the user as a non-blocking warning and recorded in the audit log And Then a background retry fetches the rule-set and reprocesses the document without ever persisting an unredacted copy
Jurisdiction-Aware Extraction Rules
"As a practitioner filing across multiple counties, I want extraction and redaction to reflect local rules so that my filings pass without avoidable rejections."
Description

Apply jurisdiction-specific rules that determine which fields are required, how they are formatted, and which redactions are permissible for each filing type and court. Version and manage rule sets by state/county, with effective dates and change history. When jurisdiction is not provided, infer likely jurisdiction from document content (e.g., court header) and prompt the user to confirm. Ensure routed fields conform to local forms and e-filing schema constraints to reduce rejections.

Acceptance Criteria
Enforce State/County-Specific Required Fields and Formats
Given a selected state, county, court, filing type, and detected document type When DocSense completes extraction Then the system enforces the jurisdiction’s rule set for required fields and formats And all missing required fields are listed with field keys and human-readable labels And field values are normalized to the jurisdiction’s format rules (e.g., date, phone, names, addresses) without loss of meaning And any field failing format rules is marked invalid with a specific error message and source location And the record cannot advance to Ready to File until all required fields pass validation
Apply Jurisdiction-Specific Redactions
Given a selected jurisdiction and filing type When routed data contains PII beyond what the jurisdiction permits for storage or sharing Then the excess PII is redacted in stored and shared copies, preserving only permitted elements And redaction is applied at character/region level and is non-reversible in exported PDFs And preserved fields required for filing remain intact and correctly mapped And a redaction summary lists each redacted field or region with the governing rule reference
Jurisdiction Inference and User Confirmation
Given no jurisdiction is provided on upload When the document contains court headers, venue references, or docket captions Then the system proposes the most likely jurisdiction (state, county, court) with a confidence score and up to three alternatives And the user must confirm or change the selection before jurisdictional rules are applied And if the top confidence is below a defined threshold (e.g., 0.70), auto-application is disabled and manual selection is required And upon confirmation, extraction results are revalidated against the chosen jurisdiction’s rules and formats
Rule Set Versioning with Effective Dates and Change History
Given multiple versions of a jurisdiction’s rule set with effective date ranges When processing a document with a filing date D (or the current date if D is absent) Then the system applies the rule version effective on that date And publishing overlapping effective date ranges is blocked with a clear error And each rule version records author, timestamp, change summary, and a diff of changed rules And the extraction record stores the applied rule version ID and its effective dates for audit
Schema Conformance for Local Forms and E-Filing
Given a jurisdiction and filing type with a defined local form or e-filing schema When mapping routed fields to the schema Then all required schema fields are populated or flagged with a blocking error specifying the field and reason And all values conform to enumerations, length limits, and regex constraints defined by the schema And disallowed extra fields are not submitted unless explicitly allowed by the endpoint And a preflight report shows zero blocking errors before enabling e-filing or form generation
Ambiguity Fallback and Safe Defaults
Given the system cannot infer a single jurisdiction or detects conflicting signals When the user reviews the upload Then the system displays Jurisdiction required and prevents routing and schema validation until set And only generic minimal redactions (e.g., SSN masking) are applied pending jurisdiction selection And the user can search and select jurisdiction by state, county, and court; upon selection, rules are applied and prior extractions are rechecked And the document is tagged Awaiting Jurisdiction for tasking and reporting until selection is made
Audit Trail for Rule Application and Redactions
Given extraction, validation, and redaction have been performed When viewing the document’s audit trail Then each routed field shows its source location(s), applied transformations, jurisdiction, rule version, and validation outcomes And each redaction shows the governing rule reference, scope, and actor (auto/manual) with timestamp And audit entries are immutable and exportable as JSON with a unique checksum And audit data visibility respects user permissions and is excluded from client-facing shares
Confidence Scoring, Validation, and Human-in-the-Loop Review
"As a two-attorney practice, I want low-confidence extractions flagged with easy verification so that we can correct issues quickly and avoid filing errors."
Description

Provide per-field and per-document confidence scores with threshold-based behaviors: auto-accept above threshold, flag for review within the intake UI when borderline, and block when low. Present side-by-side source snippets highlighting where values were extracted, allow quick corrections, and re-run downstream validations after edits. Log reviewer decisions to continuously improve models and templates. Expose webhook/event hooks so workflows can branch on confidence and validation outcomes.

Acceptance Criteria
Thresholded Confidence Scoring and Automated Accept/Flag/Block
Given a document is uploaded and parsed by DocSense When extraction completes Then the system computes per-field and per-document confidence scores in the range 0.00–1.00 with at least two-decimal precision And thresholds are applied where accept_threshold >= 0.90 and block_threshold >= 0.60 by default (and block_threshold < accept_threshold) And any field with score >= accept_threshold is marked accepted and auto-populates intake and assembly outputs And any field with block_threshold <= score < accept_threshold is marked needs_review and is not used downstream until reviewed And any field with score < block_threshold is marked blocked and prevents the document from advancing past intake to filing actions And the UI displays counts for accepted, needs_review, and blocked that match the underlying evaluation results And the per-document confidence status reflects the lowest field status (blocked if any field is blocked; needs_review if none blocked and at least one needs_review; accepted otherwise)
Borderline Items Review Queue in Intake UI
Given at least one field is evaluated as needs_review for an uploaded document When the reviewer opens the intake review panel Then all needs_review fields for that document are listed and visible within 1 second (p95) And items are sorted by ascending confidence by default with a toggle to sort by field order And each item provides actions: Accept as-is, Edit value, or Mark as Unknown And keyboard shortcuts allow A=Accept, E=Edit, U=Unknown, N=Next And upon taking an action, the item is removed from the queue and focus moves to the next item within 500 ms (p95) And the review queue counter decrements accurately and persists across page reloads
Side-by-Side Evidence Snippets for Extracted Values
Given a reviewer selects any extracted field in the review UI When the field detail panel opens Then the left pane shows the source snippet from the uploaded document with a visible bounding box and page number And the right pane shows the extracted value in an editable input with the field label and confidence score And clicking the value highlights the corresponding text region in the snippet; clicking the snippet focuses the value input And the snippet contains the exact OCR text substring used for extraction, with differences highlighted if normalization was applied (e.g., date formats) And if multiple candidate regions contributed, the UI allows switching between candidates with their individual confidence scores And the evidence and page reference are stored and retrievable in the audit trail for this field
Edits Trigger Re-Validation and Downstream Updates
Given the reviewer edits a field value and saves the change When the save succeeds Then the system re-runs only the impacted validations for the document type and jurisdiction within 3 seconds (p95) And any validation errors or warnings are surfaced inline on the field and in a summary banner And downstream assembled documents and previews reflect the new value without requiring a manual refresh And the field’s verification status is set to human_verified and its confidence retains the model score with a human_verified flag And no stale values remain in downstream payloads (webhooks, exports, assembly) after the update And if validations fail, the document remains blocked from filing actions until issues are resolved
Reviewer Decision Logging and Auditability
Given a reviewer takes any action (Accept, Edit, Mark Unknown, Reject) on a field When the action is committed Then a DecisionLog record is created capturing: user ID, timestamp (UTC), document ID, document type, field key, old value, new value, model confidence at decision time, decision type, and optional reason code And the DecisionLog record is immutable (subsequent corrections create new records with a parent reference) And sensitive PII beyond the field value is not persisted in the log; redacted snippets are referenced by ID rather than raw images/text And DecisionLog entries are queryable via UI and API with filters (date range, user, document type, field key, decision type) And DecisionLogs can be exported as CSV/JSON with access restricted to authorized roles and exports watermarked with requestor and timestamp
Confidence/Validation Webhooks and Event Delivery
Given a workspace has at least one active webhook subscription When extraction completes or any field changes state (accepted, needs_review, blocked, human_verified) or validations pass/fail Then an event is emitted with type, timestamps, document/field identifiers, prior/new state, confidence scores, jurisdiction, and correlation IDs And each delivery includes an HMAC-SHA256 signature header using the workspace secret And deliveries are attempted within 3 seconds (p95) with 5 retries using exponential backoff on non-2xx responses And an idempotency_key is included so duplicate deliveries are safely ignored by consumers And subscriptions can be enabled/disabled per event type, and test events can be fired from the UI to a sandbox endpoint And a workflow automation rule can branch based on event payload fields (e.g., proceed if all fields accepted) as verified by a test rule run
Configurable Thresholds at Global, Document-Type, and Field Levels
Given an administrator has permission to manage extraction settings When they open the Confidence Settings page Then they can configure accept_threshold and block_threshold at global, document-type, and field levels And inputs are validated to be within 0.00–1.00 and block_threshold < accept_threshold And a preview panel estimates the impact using the last 100 documents per type (e.g., counts of accepted/needs_review/blocked if applied) And changes require confirmation and are recorded in an audit log with before/after values, user, and timestamp And settings can be exported/imported as JSON and rolled back to any prior version within 30 days
Admin Configuration & Template Management Console
"As a firm admin, I want to configure document rules and monitor accuracy so that DocSense stays aligned with our workflows and compliance obligations."
Description

Offer an admin UI to manage supported document types, configure required fields by type and jurisdiction, set redaction policies, define confidence thresholds, and upload/update parsing templates. Include test harnesses for sample documents, version control with rollback, and environment-specific promotion (dev/stage/prod). Provide analytics on detection accuracy, redaction events, and time saved to inform continuous improvement and compliance reporting.

Acceptance Criteria
Supported Document Types Management
Given an Admin with Config:DocumentTypes permission is authenticated in the Admin Console, When they create a new document type with a unique key, display name, and optional aliases, Then the type is saved, appears in the document types list within 2 seconds, and becomes selectable in the template editor for the current environment. Given an Admin attempts to save a document type with a duplicate key or display name, When saving, Then the save is blocked and a uniqueness error message is displayed indicating the conflicting field. Given a document type is referenced by at least one active parsing template, When an Admin attempts to delete the type, Then deletion is blocked with a dependency warning and the Admin is offered an option to disable the type instead. Given a document type is disabled, When users upload documents, Then detection still runs but routing to templates for that type is suppressed in the current environment. Given any create, update, disable, or delete action on document types, When the action is committed, Then an audit log entry records actor, action, entity ID, before and after values, timestamp, and environment.
Required Fields Configuration by Type and Jurisdiction
Given an Admin selects a document type and jurisdiction, When they add or edit required fields with data type, validation rule, and required or optional flags, Then the configuration saves successfully and is versioned. Given a configuration contains an invalid validation rule or unsupported data type, When saving, Then the save is rejected with a validation error referencing the specific field. Given a sample document tagged for the same jurisdiction is run in the test harness, When parsing completes, Then any missing required fields are listed with field keys and a Fail: Missing Required Fields status. Given required fields are modified, When the Admin views the change history, Then previous versions and diffs are visible with author and timestamps. Given required field configurations exist for multiple jurisdictions, When the jurisdiction is changed in the console, Then the corresponding configuration loads within 2 seconds.
Redaction Policies Configuration and Enforcement
Given an Admin defines a redaction policy for a document type including field-level rules and pattern-based rules, When saving, Then rules are validated and stored with a version label. Given a sample document containing extra personally identifiable information is processed in the test harness, When the redaction policy is applied, Then only fields marked redact are masked using the selected mask style and fields marked retain for filing remain visible. Given Store Parsed Sample is enabled, When the sample is saved, Then the stored artifact is the redacted version and storage metadata indicates redacted equals true. Given a user downloads the sample from the console, When Download redacted is selected, Then the file contains the expected redactions and no raw personally identifiable information values for fields governed by the policy appear in the file text. Given any redaction policy change, When committed, Then an audit log entry is recorded and the test harness indicates the active policy version.
Detection Confidence Thresholds and Review Routing
Given an Admin sets a detection confidence threshold for a document type within 0.00 to 1.00, When a value outside the range is entered, Then saving is blocked with a range validation error. Given the threshold is set to T and a sample document yields confidence below T in the test harness, When results display, Then the document status is Needs Review and auto-population of fields is disabled. Given the threshold is set to T and a sample document yields confidence equal to or above T, When results display, Then fields are auto-populated and the status is Auto-Accepted. Given the threshold value is changed, When saved, Then the change is environment-scoped and does not affect other environments. Given the threshold is updated, When viewing the audit log, Then the previous and new values are shown with actor and timestamp.
Parsing Templates: Upload, Validation, Versioning, Rollback, and Test Harness
Given an Admin uploads a parsing template file in JSON or YAML for a document type, When the file violates the schema, Then validation fails with line and column and JSONPath pointers for each error and the version is not created. Given a valid template is uploaded with an optional changelog message, When saved, Then a new version number is assigned and it is stored in the current environment with status Draft until set active. Given a template version is set as Active, When confirmed, Then the active flag moves to that version and the test harness uses it for subsequent runs. Given the Admin selects a prior version and clicks Rollback, When confirmed, Then the prior version becomes Active and a rollback entry is recorded in audit logs. Given a sample document of size up to 10 MB is executed in the test harness against the active template, When processing completes, Then detected type, parsed fields, confidence score, and redaction preview render within 10 seconds.
Environment-Specific Promotion Workflow
Given a configuration or template version exists in Development, When an Admin with Promote:Configs permission initiates promotion to Staging, Then the system verifies dependencies exist in the target environment and that the last test harness run in Development passed; otherwise promotion is blocked with reasons. Given a promotion request to Production, When all validations pass, Then the system creates an immutable snapshot and applies it to Production, preserving version numbers and marking the promotion in the audit log. Given a configuration is promoted, When viewing environments side by side, Then the target environment reflects the promoted version as Active and other environments remain unchanged. Given a promotion is attempted that would overwrite unpromoted changes in the target environment, When detected, Then the system blocks the promotion and requires the Admin to resolve the conflict. Given a rollback is executed in Production, When confirmed, Then only the Production environment reverts to the selected prior version and the event is logged.
Admin Analytics Dashboard for Accuracy, Redaction, and Time Saved
Given an Admin selects a date range, environment, and document type filters, When Generate is clicked, Then the dashboard displays detection accuracy as a percentage, average confidence, false positives, false negatives, redaction events by field, and estimated time saved in minutes. Given the dataset contains at least 10000 documents for the selected period, When metrics are generated, Then the results render within 5 seconds and any sampling applied is indicated to the user. Given the Admin clicks Export CSV, When the export completes, Then a CSV file downloads containing the filtered metrics with headers and no raw personally identifiable information values. Given there is no data for the selected filters, When Generate is clicked, Then the dashboard shows No data for selection and all metrics display zero without errors. Given metric definitions are updated, When viewing the dashboard info tooltip, Then the current formula definitions and version are displayed.

PhotoClean

De‑skews, de‑glare, and sharpens client photos behind the scenes with live quality checks. If an image is unreadable, it sends a one‑tap retake link via SMS/WhatsApp with visual tips. Cleaner images mean higher OCR accuracy, fewer follow‑ups, and faster packet assembly.

Requirements

Real-time Image Quality Scoring
"As an intake coordinator, I want images automatically scored for readability so that only usable documents flow forward and bad captures are flagged without manual review."
Description

Implements automated, low-latency assessment of uploaded client images to detect skew, blur, glare, low contrast, cutoff edges, shadows, and insufficient resolution, returning a normalized quality score with per-issue flags. Integrates with CaseSpark intake upload endpoints and PhotoClean’s enhancement pipeline to decide pass, auto-enhance, or retake. Supports JPEG, PNG, HEIC, and rasterized single-page PDFs up to 10 MB, targeting sub-1.5s processing per image at typical intake volumes. Exposes a service API and webhook events for downstream workflow triggers, logs metrics for auditability, and preserves originals alongside derived artifacts for non-destructive processing.

Acceptance Criteria
API Returns Normalized Quality Score and Issue Flags
Given a supported image is uploaded via the intake upload endpoint When the system completes quality scoring Then the API responds 200 with a JSON body containing: imageId (UUIDv4), score (integer 0-100), flags (object with booleans: skew, blur, glare, low_contrast, cutoff_edges, shadows, insufficient_resolution), details (object with measurements: skew_deg, blur_score, glare_pct, contrast_score, edge_cutoff_pct, shadow_pct, dpi, width_px, height_px), and model_version (string) And the score value is an integer in the range 0..100 And for a known high-quality control image, score >= 90 and all flags are false And for a known degraded test image (e.g., ~20° skew, >15% glare, motion blur), score <= 40 and flags skew, glare, and blur are true And re-uploading the identical binary produces identical score and identical flags (deterministic within the same model_version)
Automated Routing: Pass, Auto-Enhance, or Retake
Given a scored image with decision rules configured as: critical_flags = {cutoff_edges, insufficient_resolution} When score >= 80 and no critical_flags are true Then decision = "pass" and no enhancement job is enqueued When 50 <= score <= 79 and no critical_flags are true Then decision = "enhance" and a PhotoClean enhancement job is enqueued with a correlationId referencing imageId When score < 50 or any critical_flags are true Then decision = "retake" and no enhancement job is enqueued And the decision field is included in the score API response And the chosen path is persisted in audit logs with imageId, decision, and score
File Format and Size Support
Given an upload of JPEG, PNG, HEIC, or rasterized single-page PDF up to 10 MB (MIME-sniffed, not extension-only) When the file is submitted to the intake endpoint Then the API accepts and scores it (HTTP 200) And EXIF orientation is honored prior to scoring for formats that support it (e.g., JPEG/HEIC) And for single-page PDF input, the page is rasterized before scoring; multi-page PDFs are rejected When the file exceeds 10 MB or is of an unsupported type (e.g., TIFF, multi-page PDF, WebP) Then the API returns an error with HTTP 413 (too large) or 415 (unsupported) and a machine-readable error code and message
Latency and Throughput Performance
Given a staging environment with representative hardware and models When processing 1,000 supported images with a steady concurrency of 20 via the intake endpoint Then the end-to-end time from POST request to scoring response has p95 <= 1.5s and p99 <= 2.5s And the error rate (non-2xx) is < 0.5% And no request times out under the configured API timeout And performance metrics are emitted per image: processing_time_ms, model_version
Webhook Delivery and Idempotency
Given a subscriber is configured with a callback URL and a signing secret When an image is scored Then a webhook event of type "image.scored" is POSTed to the subscriber with payload including imageId, score, flags, decision, and model_version And the request contains an HMAC-SHA256 signature header over the raw body and an Idempotency-Key header And on an HTTP 2xx response from the subscriber, no retries occur And on non-2xx or no response, the event is retried up to 3 times with exponential backoff (e.g., ~1s, 5s, 25s) And duplicate deliveries (same Idempotency-Key) must be safely deduplicated by the subscriber And events for the same image are delivered in sequence by increasing sequence numbers in the payload
Audit Logging and Non-Destructive Artifact Preservation
Given a supported image is uploaded When scoring and any enhancements are performed Then the original image binary is preserved unmodified with a stable storage URI and SHA-256 checksum And all derived artifacts (e.g., deskewed, deglared, sharpened) are stored with unique URIs referencing the original via imageId And audit logs capture: imageId, requestor (user/service), timestamps (received, scored, routed), decision, score, flags, processing_time_ms, model_version, and storage URIs And a retrieval API allows authorized staff to fetch the original and derived artifacts and the full audit record for the imageId
Quality Signal Accuracy on Labeled Test Set
Given a labeled validation set of >= 500 intake-style images with ground truth for each defect class When the current model_version is evaluated offline Then per-flag F1-score >= 0.85 for skew, blur, glare, low_contrast, cutoff_edges, shadows, and insufficient_resolution And skew_deg mean absolute error <= 2.0 degrees on images with skew present And glare_pct mean absolute error <= 5 percentage points on images with glare present And the normalized score is monotonic non-increasing as cumulative defect severity increases across controlled test sequences
Auto De-skew & Perspective Correction
"As a client uploading paperwork, I want my angled phone photos corrected automatically so that the documents look flat and readable without me having to re-take them."
Description

Automatically detects document boundaries and orientation, applies rotation, perspective rectification, and smart cropping to produce flat, legible outputs suitable for OCR and filing. Maintains chain-of-custody by storing original files and transformation metadata (timestamps, parameters, checksums). Ensures deterministic, idempotent operations that preserve seals, signatures, and margin annotations while exporting enhanced derivatives at 300 DPI equivalent for downstream OCR and assembly. Integrates seamlessly with PhotoClean’s quality scoring to run on fail or always-on modes as configured.

Acceptance Criteria
High-Confidence Boundary & Orientation Detection
Given a single-page document photo with distinguishable edges against background When Auto De-skew & Perspective Correction runs Then the document boundary is detected with confidence >= 0.95 And the page orientation (0, 90, 180, 270 degrees) is correctly identified And rotation and perspective rectification are applied And residual text baseline skew is <= 0.3 degrees across the page
Smart Cropping Preserves Seals, Signatures, and Margin Annotations
Given documents with stamps, seals, signatures, or handwritten notes within 5 mm of any edge When smart cropping executes Then the crop retains all detected non-background content near edges with 100% recall on the test set And a padding of at least 3% of the shorter side is retained on all edges unless content reaches the edge And no connected component > 50 pixels touching the original page boundary is partially removed
Chain-of-Custody: Originals and Transformation Metadata
Given any processed image When the derivative is saved Then the original file is stored immutably with a SHA-256 checksum And the derivative file is stored with a SHA-256 checksum And transformation metadata is recorded including: processor_version, UTC timestamp (ISO 8601), rotation angle, perspective mapping (4 corner coordinates), crop box, output pixel dimensions, assigned PPI, quality score before/after, and source_object_id linking original to derivative And all records are append-only and auditable by ID
Deterministic and Idempotent Output
Given the same input image, configuration, and processor_version When the pipeline runs three times Then the derivative byte checksum and metadata checksum are identical across all runs And reprocessing an already-processed derivative results in a no-op producing the same artifact IDs and checksums
300 DPI Equivalent Export for OCR
Given a detected page with Letter-like aspect ratio (1.25 to 1.33) When exporting the enhanced derivative Then the output resolution is 2550 x 3300 pixels ± 10 pixels and PPI metadata is set to 300 Given a detected page with A4-like aspect ratio (1.40 to 1.45) When exporting the enhanced derivative Then the output resolution is 2480 x 3508 pixels ± 10 pixels and PPI metadata is set to 300 Given other aspect ratios When exporting the enhanced derivative Then the shorter side is scaled to at least 2400 pixels and PPI metadata is set to 300
Quality Scoring Integration and Mode Control
Given mode = always_on When an image is ingested Then Auto De-skew & Perspective Correction runs automatically Given mode = on_quality_fail and quality_score < threshold T When an image is ingested Then Auto De-skew & Perspective Correction runs; else it is bypassed Given boundary detection confidence < 0.80 after two attempts When processing completes Then image_status is set to needs_retake with reason no_document_detected and the original is preserved without overwrite
Performance and Throughput Targets
Given a 12 MP input image on a standard processing worker When Auto De-skew & Perspective Correction runs Then P95 end-to-end processing time per image is <= 2.0 seconds and P99 is <= 4.0 seconds And memory usage remains <= 500 MB per worker during processing Given 10 concurrent images When processed in parallel on one worker Then P95 per-image latency is <= 2.5 seconds
OCR-Optimized Enhancement Pipeline
"As a solo attorney, I want images enhanced for OCR automatically so that data extraction is accurate and I spend less time fixing misreads."
Description

Provides a tunable preprocessing pipeline—denoise, deblur/sharpen, contrast normalization, adaptive binarization, and glare suppression—that generates OCR-ready variants while preserving critical visual elements (stamps, signatures, seals). Produces both a clean text-optimized image and a fidelity-preserving color image, selects the best for OCR based on confidence, and attaches OCR confidence metrics to the case record. Falls back to retake flow when confidence drops below threshold. Outputs searchable PDF derivatives for CaseSpark’s document assembly and stores step-by-step processing metadata for audit.

Acceptance Criteria
Configurable Enhancement Pipeline Executes in Order
Given a newly uploaded document image with a processing profile specifying step order (denoise → deblur/sharpen → contrast normalization → adaptive binarization → glare suppression) When the enhancement pipeline runs Then the pipeline executes only the enabled steps in the specified order And each executed step records parameters used, start/end timestamps, and produces an intermediate artifact linked to the case And any disabled step is skipped and logged as skipped And per-matter or per-document overrides supersede global defaults and are reflected in the metadata
Dual Outputs: Text-Optimized and Color-Fidelity Variants
Given a single-source input image When processing completes Then the system outputs two derivatives: (1) a text-optimized image (grayscale/binarized) at effective resolution ≥ 300 DPI and (2) a color-fidelity image preserving original color space And both derivatives preserve full page geometry with no unintended cropping or aspect distortion And both files are stored, versioned, and linked to the originating case record with distinct labels And per-page file size does not exceed 1.5 MB for text-optimized and 6 MB for color-fidelity unless an approved size override is configured
Best-Variant Selection and OCR Confidence Attachment
Given multiple processed variants are available for OCR When OCR is executed on all available variants Then the system selects the variant with the highest average page-level OCR confidence for text extraction And per-variant metrics (page-level average confidence, word-level confidence histogram, and rejection rate) are recorded And the selected variant’s confidence metrics are attached to the case record and surfaced via API/UI And the configured selection rule and confidence threshold used at decision time are recorded in metadata
Preservation of Critical Visual Elements
Given documents containing stamps, signatures, or seals with auto-detected or annotated bounding boxes When the enhancement pipeline completes Then each critical element region retains visual integrity with similarity ≥ 0.95 to the source (e.g., SSIM or keypoint match) within its bounding box And foreground pixel coverage within each bounding box is ≥ 90% of the source after binarization/contrast adjustments And no critical element region is clipped, erased, or merged into background And if a step threatens preservation, the pipeline reduces aggressiveness for that region and logs a preservation warning
Confidence Threshold Triggers Retake Flow
Given a configurable OCR confidence threshold T for the workspace When the selected variant’s average page-level confidence is < T Then the image is not marked OCR-ready and the retake flow is initiated And a one-tap retake link with visual capture tips is sent via SMS or WhatsApp to the client’s verified number within 5 seconds And the retake link expires after 24 hours and is rate-limited to prevent spam And all notification attempts, deliveries, and failures are logged and visible in the case timeline And if no deliverable channel exists, the case is flagged for manual follow-up with a high-priority alert
Searchable PDF Derivatives for Document Assembly
Given processed images and corresponding OCR text When PDF export is requested or triggered automatically Then a searchable PDF is generated with an embedded text layer aligned to the image (word bounding boxes within ±3 pixels of OCR positions) And the PDF opens in standard viewers with selectable and copyable text and correct orientation And the derivative is attached to the case record and becomes available to document assembly within 1 minute of image upload And the PDF includes page-level metadata referencing source image IDs and processing version
Processing Metadata Audit Trail
Given any image that has been processed by the enhancement pipeline When the audit log is retrieved via API or UI Then the log contains a complete step-by-step record including algorithm names/versions, parameter values, timestamps, hardware/context identifiers, variant lineage, selected OCR confidence, and the threshold T used And the audit records are immutable and tamper-evident with unique IDs and checksums And metadata export is available in JSON and retained for at least 7 years per retention policy
One-Tap Retake Links (SMS/WhatsApp)
"As a client on my phone, I want a simple retake link with clear guidance so that I can quickly fix bad photos without logging into a portal."
Description

When images fail quality thresholds, sends a secure, short-lived deep link via SMS or WhatsApp that opens a lightweight capture flow with device-optimized settings and instant upload back to the same intake session. Supports localization, branded templates, rate limiting, resend, and email fallback. Tracks delivery and completion events, associates retakes with the original request, and updates the matter timeline. Links are tokenized, expiring, and scoped to the specific document request to protect client privacy.

Acceptance Criteria
Auto-Send Retake Link on Failed Quality Check (SMS/WhatsApp)
- Given a client upload fails PhotoClean quality thresholds, When the failure is confirmed, Then the system sends exactly one retake deep link via the client's preferred channel (WhatsApp if available and consented, else SMS) within 3 seconds. - Given the client's phone number is E.164-valid, When the message is sent, Then the message includes the practice brand name, document name, and a single-use deep link and excludes any PII beyond first name and document name. - Given an intake session and a specific document request, When the retake link is generated, Then the link is uniquely tied to that document request and session and cannot be used to access any other matter or file. - Given a transient send failure occurs, When the initial send fails, Then the system retries up to 2 times with exponential backoff and surfaces final success/failure in the CaseSpark UI.
Deep Link Opens Lightweight Capture Flow with Device-Optimized Settings
- Given a recipient taps a valid, unexpired deep link on a mobile device, When the link is opened, Then a browser-based capture flow loads in under 2 seconds without requiring login. - Given the capture flow is active, When the device camera is used, Then deskew guidance, anti-glare hints, and sharpness indicators are displayed and capture resolution is optimized for the device with resulting file size ≤ 5 MB per image. - Given the client captures a replacement image, When they submit, Then the image uploads to the original intake session and shows a success confirmation within 3 seconds on a 4G connection. - Given multiple pages are requested, When each page is submitted, Then progress is displayed and all pages are uploaded and linked to the same document request.
Secure Tokenization, Scope, and Expiry of Retake Links
- Given a retake link is generated, When the URL is inspected, Then it contains a cryptographically random token with ≥128-bit entropy and no PII. - Given an unexpired token, When the deep link is used, Then access is limited to uploading retakes for the specified document request within the originating intake session only. - Given the configured expiry window (default 15 minutes, configurable 5–60 minutes) elapses, When the user taps the link, Then access is denied with an expiry message and an option to request a new link. - Given a token is redeemed successfully, When the same token is used again, Then the attempt is rejected, logged as a replay, and no data is exposed.
Localization and Branded Templates for Retake Messages
- Given a client’s preferred language is available, When the retake message is sent, Then the content and visual tips are localized using the approved template and practice brand assets. - Given the preferred language is unavailable, When the message is sent, Then the content falls back to English and the fallback is logged for localization reporting. - Given brand configuration exists for the practice, When the message is rendered, Then the practice name and logo (for WhatsApp) are shown and links use the practice-branded domain. - Given dynamic fields are required, When the message is sent, Then placeholders for client first name and document name are populated correctly.
Rate Limiting and Resend Controls
- Given a specific document request, When retake links are sent, Then no more than 3 links may be sent per 24-hour period and no more than 1 per 60 seconds. - Given a user clicks Resend in CaseSpark, When limits are not exceeded, Then a new tokenized link is generated, all prior tokens for that request are invalidated, and the message is sent with a Resent tag. - Given rate limits are exceeded, When a resend is attempted, Then the send is blocked, the UI displays remaining cooldown time, and an audit entry is recorded. - Given an automatic send is triggered by a new quality failure, When a resend was sent within the last 2 minutes, Then the system suppresses the duplicate and flags the document request as Pending retake without sending another link.
Email Fallback When SMS/WhatsApp Undeliverable
- Given SMS/WhatsApp delivery fails or no mobile number exists but a verified email is present, When two send attempts fail or no eligible channel exists, Then an email with the retake deep link is sent within 60 seconds using the practice’s email template. - Given the email is delivered, When the client opens the link, Then the same capture flow launches and token scope/expiry rules apply identically. - Given the email hard-bounces, When the provider webhook is received, Then the intake owner is notified in CaseSpark with recommended next steps and the failure is logged.
Delivery, Completion, and Timeline Association
- Given a retake message is sent, When provider webhooks are received, Then send, delivery, and failure statuses are recorded within 5 seconds and visible in the matter activity log. - Given a client opens the retake link, When the page loads, Then an Opened event is recorded with timestamp, channel, and device type. - Given the client uploads a retake image, When the upload succeeds, Then the image is associated to the original document request, the request status updates to Retake received, and the matter timeline gains an entry with thumbnail and actor Client. - Given all requested pages are retaken, When processing completes, Then a Retake complete event is recorded, OCR is re-queued automatically, and analytics counters are incremented.
Live Capture Guides & Visual Tips
"As a client unfamiliar with scanning, I want live on-screen guidance while taking a photo so that I capture an acceptable image on the first try."
Description

Provides real-time capture assistance in the mobile/web retake flow, including edge detection overlays, tilt and alignment indicators, glare and blur warnings, and short visual tips for common issues. Uses on-device checks to prevent low-quality captures before submission and gracefully degrades to gallery upload when camera access is unavailable. Designed for accessibility with clear contrast, concise copy, and multilingual support, and instrumented to report anonymized quality outcomes for continuous improvement.

Acceptance Criteria
Real-Time Edge Detection & Alignment Overlay
Given the retake flow is opened with camera access When a rectangular document enters the frame Then document edges are highlighted within 300ms of movement And the edge/corner overlay updates at least 10 FPS while the camera preview is active And a tilt indicator appears when roll or pitch exceeds 5 degrees and clears when below 3 degrees for 500ms And guides do not obscure the capture button or critical on-screen instructions
On-Device Quality Gate (Blur, Glare, Skew, Coverage)
Given the user attempts to capture a photo in the retake flow When any quality check fails (variance of Laplacian < 100 indicating blur, glare area > 12% of document area, skew > 8 degrees, or fewer than 3 edges detected, or document coverage < 70% of frame) Then the Use Photo action is disabled and a Retake prompt is shown And a specific warning badge is displayed for each failing check (Blur, Glare, Skew, Edges, Fill Frame) And when all checks pass for 2 consecutive frames, the Use Photo action is enabled And all checks execute fully on-device with no network calls and function in airplane mode
Contextual Visual Tips for Common Issues
Given a specific capture issue is detected (glare, blur, misalignment, low coverage, shadows) When the corresponding warning is triggered Then a visual tip card appears within 500ms containing an icon and no more than 90 characters of copy And the tip is localized to the active language and is dismissible by tap And the tip auto-hides after 5 seconds once the condition is resolved And at least these tips are available: Remove glare (tilt or move light), Hold steady 2s, Align edges to frame, Fill the frame, Avoid shadows
Graceful Fallback to Gallery Upload When Camera Unavailable
Given the retake flow starts and camera permission is denied or no camera is present When the capture view initializes Then the user is shown a Gallery Upload option within 1 second and the app does not crash And an Open Settings action is provided for permission recovery on supported platforms And when a gallery image is selected, the same on-device quality checks run before enabling submission And the fallback flow functions on mobile web (Safari/Chrome) and desktop web without requiring additional installs
Accessibility Compliance for Capture Guides
Given the capture guides and tips are displayed Then text and icon overlays meet a contrast ratio of at least 4.5:1 against the live preview And all interactive controls have a minimum touch target of 44x44 px/pt And screen readers announce warnings and tips when they appear, with accessible names and roles on all controls And keyboard navigation on web follows a logical focus order with visible focus indicators And dynamic type/scaled text up to 200% does not clip or overlap critical content
Multilingual Support & Language Switching
Given the device/browser locale is English or Spanish When the retake flow opens Then all guides, warnings, and tips render in the detected locale within 1 second And a language switcher allows manual override between available languages without restarting the flow And 100% of capture-related strings are localized for supported locales with no unintended English fallbacks And RTL-safe styles prevent layout breakage if an RTL locale is enabled
Anonymized Quality Telemetry & Outcomes
Given a capture session occurs When the user completes or exits the retake flow Then a telemetry event is queued with: anonymized session ID, device model, OS version, language, camera permission state, number of retakes, final outcome (accepted/rejected), blur/glare/skew metrics, time to first overlay, time to first successful capture And no image pixels, contact info, names, or precise geolocation are collected And 95% of telemetry events are delivered within 24 hours with retries and exponential backoff And telemetry sending does not block UI interactions or capture completion
Admin Thresholds & Workflow Controls
"As a firm owner, I want to control quality thresholds and messaging behavior so that PhotoClean matches our risk tolerance and client experience standards."
Description

Exposes firm-level settings to tune quality thresholds, choose auto-enhance versus immediate retake prompts, configure message templates and languages, and route failures to a manual review queue when desired. Allows per-intake-step overrides (e.g., stricter thresholds for court filings), scheduled quiet hours for messaging, and branding controls. Includes role-based access, audit trails for configuration changes, and preview/testing tools to validate settings before rollout.

Acceptance Criteria
Global Quality Thresholds & Automation Policy
Given I am an Org Admin on Settings > PhotoClean > Quality Controls When I set blur_threshold=0.35, glare_threshold=0.20, skew_threshold=4 degrees and select policy="Auto-enhance first; if still below thresholds send retake" And I click Save Then the settings persist across session reload and are versioned with an incremented config version ID And new images processed after 60 seconds use the saved thresholds and policy And if pre-enhancement metrics are below thresholds the system performs exactly one enhancement pass And if post-enhancement metrics meet or exceed all thresholds no retake message is sent And if any post-enhancement metric remains below threshold a retake message is sent immediately And processing logs for the image record pre/post metrics, policy path taken, and config version used
Per-Step Overrides & Precedence
Given default quality thresholds and policy are configured And I create an override for intake step "Court Filing > Exhibits" with blur_threshold=0.25, glare_threshold=0.15, skew_threshold=2 degrees and policy="Immediate retake; skip enhancement" When an image is uploaded during the "Court Filing > Exhibits" step Then the override thresholds and policy are applied instead of the defaults And an image uploaded at steps without an override uses the default settings And if multiple overrides could apply, the most specific step path takes precedence; if equally specific, the most recently activated override applies And removing or disabling the override reverts processing to defaults within 60 seconds And the step-level Preview shows pass/fail outcomes for at least 3 sample images using the override
Messaging, Localization, Quiet Hours, and Branding
Given I can edit SMS/WhatsApp templates with placeholders {client_first_name}, {retake_link}, {tips_image} And I add locales en-US and es-ES with firm-approved copy And I configure quiet hours 20:00–08:00 using the firm’s timezone And I upload a square logo (<= 1MB, PNG/SVG) and set brand primary color #0047AB When I click Test Send to a specified number for locale es-ES Then the message renders with placeholders resolved, correct locale text, and active retake link And messages triggered during quiet hours are queued and sent at 08:00 local time; queued count and next-send time are visible And if a client’s preferred language is unsupported the system falls back to en-US And the retake landing page displays the uploaded logo and brand color and passes a contrast check of WCAG AA for body text And if SMS fails once the system retries once and, on failure, attempts WhatsApp once; all outcomes are logged
Manual Review Queue & Notifications
Given "Route failures to Manual Review" is enabled with reviewer role=Intake Reviewer and SLA=4 business hours When an image fails thresholds under the current policy and is configured to route to manual review Then a review item is created within 30 seconds with the image, measured metrics, intake step, client identifier, and failure reason And Intake Reviewers can Approve as-readable, Request Retake (one-tap link), or Reprocess after adjusting per-item thresholds; each action is recorded And items approaching SLA breach (15 minutes remaining) trigger an in-app alert and email to the reviewer group; breaches are marked overdue And closing the item updates the intake record and, if retake requested, enqueues messaging respecting quiet hours
Role-Based Access Controls
Given roles are defined as Org Admin (manage), Intake Manager (view + run previews/tests), Staff (view-only), Auditor (view audit only) When a user with each role accesses Settings > PhotoClean > Admin Thresholds & Workflow Controls Then only Org Admin can create, edit, or delete configurations And Intake Manager can view configurations and run previews/tests but cannot save changes And Staff can view effective (read-only) settings but cannot access previews/tests or edit And Auditor can access the audit trail but not settings pages And unauthorized actions return HTTP 403 in API and are blocked in UI with a permission message
Configuration Audit Trails
Given audit logging is enabled for configuration changes When any setting under Admin Thresholds & Workflow Controls is created, updated, or deleted Then an immutable audit record is stored with timestamp (UTC), actor user ID, role, IP, action, target key, before_value, after_value, config version, and optional reason note And Org Admin and Auditor roles can filter and view audit entries by date range, actor, and key And audit entries can be exported as CSV and JSON for a selected date range And audit entries cannot be edited or deleted; any redaction is recorded as a new audit entry referencing the original
Sandbox Preview & Test Harness
Given a Preview & Test tab is available When I select a configuration version and upload or select 3 sample images Then the system performs a dry run showing per-image metrics, thresholds applied, step override used, enhancement attempts, and the resulting action (approve/retake/manual review) without altering production data And I can send a test retake message to a test phone number that bypasses quiet hours and is flagged as TEST in logs And I can generate a shareable preview link valid for 24 hours for internal review And I can schedule rollout of the selected configuration version with an effective start time and rollback to the prior version in one action; both actions are audited
Privacy, Security & Audit Logging
"As a compliance-conscious attorney, I want secure processing with detailed audit trails so that I can defend image integrity and meet ethical obligations."
Description

Applies encryption in transit and at rest, scoped access controls, and configurable retention to protect sensitive client images. Records a tamper-evident audit log of all transformations, quality decisions, and outbound messages tied to the matter. Supports region-aware data residency, consent capture for messaging, and redaction of sensitive overlays when generating previews. Provides exportable audit reports to support court challenges and firm compliance policies.

Acceptance Criteria
End-to-End Encryption for Client Images
Given any client image is uploaded, when it transits any network boundary, then TLS 1.2+ with modern ciphers (e.g., TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 or stronger) is enforced and HSTS is enabled. Given any client image or derivative is stored (including caches and backups), when data is written at rest, then it is encrypted using AES-256 with KMS-managed keys scoped per tenant and matter. Given key lifecycle operations occur, when rotation or revocation is initiated, then keys are rotated without data loss, older keys are disabled within 15 minutes, and all events are logged with actor, timestamp, and reason. Given an unencrypted endpoint or weak cipher is negotiated, when a client attempts connection, then the request is rejected with 403 and a security event is recorded with client IP and user agent.
Role- and Matter-Scoped Access Controls
Given a user requests to view, download, transform, or preview an image for a matter, when their role lacks the required permission or they are not assigned to the matter, then access is denied with 403 within 200 ms and the attempt is logged (user, role, matter ID, action, outcome). Given background services perform transformations or quality checks, when they access image data, then service accounts are least-privilege, scoped to the tenant/matter, and cannot enumerate or access data from other matters. Given a user’s role changes or they are removed from a matter, when the next access is attempted, then permissions reflect the change immediately (≤60 seconds propagation) and prior access tokens are invalidated. Given API tokens are used, when a token lacks the required scopes, then operations are blocked and the response includes an error code indicating insufficient scope.
Configurable Retention and Secure Deletion Policies
Given a tenant sets a retention policy (e.g., X days after upload or Y days after matter close), when the retention threshold is reached, then originals, derivatives, previews, and caches are queued for deletion within 24 hours and hard-deleted from primary storage within 7 days. Given deletion is executed, when purge completes, then related CDN/cache entries are invalidated within 15 minutes and a signed deletion receipt is added to the audit log. Given a legal hold is placed on a matter, when retention thresholds are reached, then deletion is paused until the hold is removed and the hold state is visible in admin UI and via API. Given retention settings are changed, when policies are updated, then changes apply prospectively and an audit event records the before/after values, actor, and justification.
Tamper-Evident Audit Log & Exportable Compliance Report
Given PhotoClean performs a transformation, quality decision, access check, or sends an outbound message, when the event occurs, then an append-only audit record is written with ISO-8601 timestamp, tenant ID, matter ID, actor (user/service), action, parameters summary, outcome, and cryptographic hash of related artifacts. Given audit records are appended, when integrity is verified, then a hash-chained log (SHA-256) validates continuity and any gap or mutation causes verification to fail with an alert. Given an authorized admin requests an audit export for a matter and date range, when the request is submitted, then a signed export (JSONL and PDF summary) with integrity proof (Merkle root + signature) is generated within 60 seconds for up to 100k records and made available for download and secure push to firm storage. Given a consumer validates an export, when the signature and chain are checked via the verification endpoint, then the API returns Pass/Fail with details on any broken chain segment.
Region-Aware Data Residency Enforcement
Given a tenant’s data region is configured (e.g., US, EU), when images are stored or processed, then all at-rest storage, backups, and compute for PhotoClean remain in-region; cross-region transfers are blocked by policy. Given a disaster recovery failover occurs, when regional capacity is impaired, then failover only occurs to an approved paired region defined for the tenant; otherwise processing is halted and admins are notified within 5 minutes. Given outbound messaging is initiated, when SMS/WhatsApp gateways are selected, then region-appropriate gateways are used and message payloads (including images and links) are kept in-region. Given a DPA-approved exception is granted, when a cross-region transfer is required, then explicit admin approval and legal basis are captured, scope and duration are enforced, and the exception is auto-revoked upon expiry.
Messaging Consent Capture & Enforcement for Retake Links
Given a retake link needs to be sent via SMS or WhatsApp, when no valid channel-specific consent exists for the client and matter, then the send is blocked with a 412 Precondition Failed and an in-product prompt enables capturing consent. Given a client provides consent (tap to agree or approved keyword flow), when consent is recorded, then the record includes channel, timestamp, purpose, locale, matter ID, and expiry; subsequent messages reference this consent ID. Given a retake link is sent, when the message is delivered, then it includes opt-out instructions, the link token expires within 24 hours by default (tenant-configurable), and all message events (queued, sent, delivered, failed, clicked) are logged to the matter. Given a client opts out (e.g., STOP), when an outbound send is attempted, then messaging is prevented for that channel and matter, and the UI/API surfaces the opt-out state.
Sensitive Overlay Redaction in Preview Generation
Given a preview or thumbnail is generated for staff or client viewing, when sensitive overlays (e.g., SSNs, DOBs, bank numbers) are detected by pattern and ML models, then those regions are redacted (box blur or solid fill per policy) before the preview is stored or displayed. Given OCR processing is performed, when redaction is applied to previews, then OCR continues on the original non-redacted image in secure processing space and the original is never exposed in previews without elevated permission. Given a user with elevated permission requests to view an unredacted preview, when just-in-time approval is granted, then access is allowed for a maximum of 15 minutes, watermarked, and fully audited (who, when, why). Given preview files are produced, when metadata is written, then all EXIF/GPS and camera identifiers are stripped from previews and thumbnails prior to storage and delivery.

GapPrompt

Sends micro‑prompts via text to collect any missing or ambiguous details—like full middle names, child birth dates, or last‑4 phone digits for disambiguation. Tone‑aware, bilingual, and time‑window respectful, it boosts completion rates without phone tag or manual chasing.

Requirements

Gap Detection & Structured Parsing Engine
"As an intake attorney, I want the system to automatically detect missing or ambiguous data and collect it via SMS so that matters can move to conflict check and document assembly without manual chasing."
Description

Implements real-time detection of missing or ambiguous intake data against matter-type and jurisdiction-specific schemas, including fields required for conflict screening and document assembly. Triggers context-aware micro‑prompts when gaps are found, selecting the minimum set of questions to reach completeness. Parses inbound SMS replies into structured values (e.g., names, dates, addresses, identifiers) using format validation, regex/NLP, and jurisdictional constraints, with inline error handling and confirmation prompts when needed. Writes validated values back to the intake record, emits events for conflict screening and document assembly, and logs decisions for traceability.

Acceptance Criteria
Schema-Driven Real-Time Gap Detection (CA Divorce—With Minor Children)
Given an active intake for matter type "CA Divorce — With Minor Children" and jurisdiction "CA" and the record is missing child.first_name and child.date_of_birth required by the schema When the Gap Detection engine evaluates the record in real time Then it identifies exactly the set of missing or ambiguous fields required for conflict screening and document assembly And composes a micro-prompt plan containing the minimum number of questions to reach schema completeness (no more than 2 prompts for the missing child fields in this example) And excludes any fields not required by this schema And completes evaluation within 500 ms for records with ≤ 50 fields And persists a gap-detection snapshot including timestamp, schema_version, jurisdiction, and the list of missing/ambiguous fields
Ambiguity Resolution via Minimal Disambiguator (Duplicate Contact Match)
Given two existing contacts named "Alex Kim" in CRM and an intake party "Alex Kim" with an ambiguous match When the engine detects ambiguity and prompts for a single disambiguator per policy order (last 4 of mobile, else DOB) Then it sends exactly one micro-prompt requesting the highest-ranked available disambiguator And upon reply "4821" it matches to exactly one contact with that last-4 and resolves the ambiguity And records the chosen disambiguator and outcome, links the party to the matched contact, and does not issue further disambiguator prompts And if the reply does not resolve (none or multiple matches) it escalates by sending the next policy disambiguator prompt (max 2 total) and logs the reason for escalation
Structured Parsing: Full Legal Name and DOB from Single SMS
Given a micro-prompt requesting full legal name and date of birth in format MM/DD/YYYY When the user replies "Maria del Carmen Reyes 12/03/2012" Then the engine extracts legal_name="Maria del Carmen Reyes" and dob="2012-12-03" (ISO) using format validation and NLP tokenization And validates dob is between 1900-01-01 and today and not in the future And echoes a confirmation "Please confirm: Name: Maria del Carmen Reyes; DOB: 12/03/2012 (Yes/No)" And on "Yes" it marks both fields validated and writes them to the intake record And on "No" it rejects the values and sends a corrective prompt with examples And if the reply omits a 4-digit year (e.g., "12/03") it sends an inline error requesting MM/DD/YYYY and does not update the record
Jurisdictional Address Validation and Normalization (US—USPS and County)
Given a prompt to provide the residential address for a CA family-law matter When the user replies "101 5th St, San Jose CA 95112" Then the engine parses street="101 5th St", city="San Jose", state="CA", zip="95112" And validates state code, ZIP format, and city/ZIP/state consistency against USPS metadata And normalizes components to USPS standards and derives county="Santa Clara" And if any inconsistency is detected it sends a single corrective micro-prompt and defers write-back until corrected And upon user confirmation of the normalized address it writes the address and county to the intake record and marks the address field group complete
Atomic Write-Back and Event Emission with Idempotency Guarantees
Given one or more validated field values are ready to persist When the engine writes values back to the intake record Then it performs an atomic upsert and returns a single success/failure outcome And emits events: "conflict_screening.ready" when all conflict-required fields are complete and "doc_assembly.field_update" for each updated field And each event includes record_id, correlation_id, jurisdiction, schema_version, and field_names And if the same SMS reply is received more than once within 5 minutes it does not create duplicate writes or duplicate events (idempotent by correlation_id) And median time from SMS receipt to event emission is ≤ 2 seconds
Traceability and Decision Logging for Prompts and Parsing
Given any gap detection, prompt generation, reply parsing, validation error, or write-back occurs When the action is executed Then an audit log entry is written containing timestamp, intake_id, correlation_id, actor="engine", action_type, input_text (PII-handled per policy), detected_entities, rules_applied, decision_reason_codes, and outcome And logs are queryable by intake_id and correlation_id within 2 seconds And logs are retained for ≥ 2 years and can be exported in JSONL format
Bilingual Handling and "No Middle Name" Interpretation (Spanish)
Given the contact’s preferred language is Spanish and the middle name is ambiguous (e.g., current value "M.") When the engine prompts for the full middle name Then it sends the micro-prompt in Spanish with guidance to reply "No tengo segundo nombre" if none And when the user replies "No tengo segundo nombre" the engine sets middle_name=null and middle_name_has_no_value=true and marks the field complete And it sends a Spanish confirmation summarizing the applied change And if the user replies with a name containing diacritics (e.g., "José") the parser preserves Unicode characters in the stored value
Tone‑Aware Bilingual Messaging
"As a client, I want to receive clear, respectful prompts in my preferred language and tone so that I can respond quickly and confidently."
Description

Delivers micro‑prompts in English and Spanish with selectable tone (professional, neutral, friendly) and reading level, honoring client language preference inferred from intake data, device locale, or past behavior. Supports variable interpolation, gendered language considerations, diacritics, and punctuation safe for carriers. Includes translation quality controls, fallback language rules, and persistent preference storage to ensure messages are clear, respectful, and quick to answer.

Acceptance Criteria
Infer and Apply Client Language Preference
Given a client profile with an explicit language preference of Spanish When a micro‑prompt is sent Then the message language is Spanish and decision_source="profile" is logged Given no explicit preference but the last two client inbound messages were in Spanish When a micro‑prompt is sent Then the message language is Spanish and decision_source="behavior" is logged Given no explicit preference/behavior and the device locale is es‑MX When a micro‑prompt is sent Then the message language is Spanish (region=MX recorded) and decision_source="device" is logged Given no explicit preference, behavior, or device locale When a micro‑prompt is sent Then the message language is English and decision_source="default" is logged Then the chosen language is persisted to the client profile with a timestamp and message_id
Selectable Tone Rendering
Given tone=professional When composing the message Then the output contains no contractions, no emojis, and uses formal salutations/openings and closings Given tone=neutral When composing the message Then the output uses plain language with 0–1 polite markers and no exclamation marks Given tone=friendly When composing the message Then the output may use contractions (EN) or casual equivalents (ES), at most one exclamation mark total, and maintains respectful phrasing Then the selected tone value is recorded in send metadata and applied consistently across all segments of the message
Reading Level Enforcement (EN/ES)
Given reading_level=Grade 6 and language=English When generating the message Then the Flesch‑Kincaid Grade Level is <= 6.9 Given reading_level=Grade 8 and language=English When generating the message Then the Flesch‑Kincaid Grade Level is <= 8.9 Given reading_level=Sencillo and language=Spanish When generating the message Then the Fernández‑Huerta score is >= 80 Given reading_level=Claro and language=Spanish When generating the message Then the Fernández‑Huerta score is >= 65 If the computed readability does not meet the target Then a simpler pre‑approved variant is selected automatically and the resulting message meets the threshold
Variable Interpolation and Carrier‑Safe Delivery
Given a template containing {first_name}, {case_type}, and {due_date} When composing the message Then all placeholders are replaced with resolved values or configured fallbacks (e.g., "[your name]") and no raw placeholders remain in the final text Then smart punctuation (curly quotes, ellipses, non‑breaking spaces, zero‑width chars) is normalized to carrier‑safe equivalents Then diacritics are preserved; if non‑GSM‑7 characters are present, encoding=UCS‑2 is used and segment_count is calculated If segment_count exceeds the configured limit (e.g., 3) Then the system applies the concise variant or prompts to shorten before send, and the final sent message is within limit Then the audit log captures template_id, resolved variables, final text, encoding, and segment_count
Spanish Gendered Language and Neutral Defaults
Given language=Spanish and client_gender=Female When composing salutations/adjectives Then feminine forms are used where applicable (e.g., "Estimada") Given language=Spanish and client_gender=Male When composing salutations/adjectives Then masculine forms are used where applicable (e.g., "Estimado") Given language=Spanish and client_gender is Unknown or Non‑binary When composing the message Then neutral phrasings that avoid gendered forms are used (e.g., "Hola {first_name}", "Buen día") Then gendered terms are suppressed if a client preference flag "use_neutral_language" is true, regardless of stored gender
Translation Quality Control and Fallback Rules
Given a source template in English and target=Spanish When translating the message Then glossary‑protected legal terms are preserved per glossary and placeholders retain order and form Then the translation quality score (e.g., COMET or equivalent) is >= 0.75 OR a pre‑approved human‑reviewed target template is used If the quality score is below threshold or a glossary conflict is detected Then the system falls back to a pre‑approved target variant or to English (as configured) and logs fallback_reason Then a sampling process (configurable rate) routes a subset of bilingual messages to QA with outcomes recorded (Pass/Fail, notes)
Persistent Preference Storage and Real‑Time Overrides
When a message is sent Then the effective language, tone, and reading_level are saved to the client’s preferences with timestamp and actor (system/user) Given the client replies in a different language or sends a keyword ("ESPAÑOL"/"ENGLISH") When the reply is processed Then the preferred language is updated immediately and confirmed in the new language Given a per‑send override is selected by an agent When the message is sent Then the override applies to that message only unless "Save as default" is selected, in which case the stored preference updates Then all preference changes and overrides are audit‑logged with before/after values
Time‑Window & Frequency Controls
"As a client, I want prompts only at reasonable times and not too often so that I’m not disturbed and more likely to respond."
Description

Respects the client’s local timezone with automatic detection and configurable quiet hours, business-day windows, and holiday calendars. Provides cadence controls including max attempts, minimum spacing, adaptive throttling after partial responses, snooze/reschedule options, and automatic pause on active conversations or agent takeover. Enforces do‑not‑contact flags and consent status before sending, ensuring a non-intrusive, higher-conversion outreach rhythm.

Acceptance Criteria
Local Timezone Detection & Quiet Hours Enforcement
Given a client with a resolvable local timezone (from verified address, prior interactions, or phone metadata) and firm-configured quiet hours When a GapPrompt send is due during the client’s quiet hours Then the message is queued and not sent until the next allowed window in the client’s local timezone Given a client without a resolvable timezone When a GapPrompt is scheduled Then the firm default timezone is used and the event is flagged in the audit log for timezone review Given a DST transition day for the client’s timezone When evaluating quiet hours Then the evaluation uses the correct post-transition local time and no messages are sent within quiet hours Given a queued message becomes eligible to send at the window open When the window opens Then the message is sent within a configurable SLA (default ≤5 minutes) and the audit trail records timezone, quiet-hour window, and decision outcome
Business-Day Windows & Regional Holiday Suppression
Given firm-configured business-day windows (e.g., Mon–Fri, 9:00–18:00 local) and a selected regional holiday calendar for the client’s locale When scheduling GapPrompts Then sends occur only within the configured business-day time window and are suppressed entirely on listed holidays Given multiple possible jurisdictions for a client When determining holiday applicability Then the system applies the holiday calendar mapped to the client’s primary locale and logs the calendar used Given a send is suppressed due to a holiday or outside business hours When the next valid window begins Then the message is automatically rescheduled for the earliest valid time respecting quiet hours and minimum spacing
Cadence Controls: Max Attempts and Minimum Spacing
Given a cadence configuration with max attempts (e.g., 5) and minimum spacing (e.g., 6 hours) for a prompt sequence When a GapPrompt campaign runs for a client Then the system never sends more than the configured max attempts and enforces at least the configured minimum spacing between sends Given a client responds completing the requested data When evaluating remaining attempts Then all further attempts in that sequence are canceled Given attempts are exhausted When the last attempt is sent Then the sequence status is set to Completed – Max Attempts Reached and no further automated messages are sent
Adaptive Throttling After Partial Responses
Given a client sends any partial response in the sequence When scheduling subsequent prompts Then the system increases the minimum spacing by the configured throttle factor (default 2×) and limits to at most one automated follow-up in the next 24 hours Given continued partial engagement (e.g., multiple replies within 48 hours) When recalculating cadence Then the system maintains the throttled spacing until either all required data are completed or there is 48 hours of inactivity Given adaptive throttling changes a previously scheduled send time When applying the new schedule Then the prior send is canceled and the new time is set, respecting quiet hours and business-day windows
Client and Staff Snooze/Reschedule
Given a client replies with a deferment intent (e.g., "later", "tomorrow", "in 2 hours") When natural-language time parsing succeeds Then the sequence is snoozed until the interpreted time in the client’s local timezone, adjusted to the next allowed window if it falls within quiet hours Given a staff user clicks Snooze in the dashboard with a specific duration or date/time When saving the action Then automated sends pause until that time and an audit entry records the actor, duration, and reason Given an active snooze is in effect When the snooze expires Then the next pending prompt is sent at the earliest allowed time honoring minimum spacing and throttle rules
Auto-Pause on Active Conversation or Agent Takeover
Given an active two-way conversation (client inbound within the last 10 minutes) or an agent marks Takeover When an automated send is due Then the system pauses automated prompts and does not send during the active window Given no further client inbound messages for the cooldown period (default 60 minutes) and no active takeover flag When reevaluating the schedule Then the sequence resumes at the next allowed time, preserving minimum spacing and quiet-hour constraints Given a send was skipped due to pause When resuming Then the system requeues the next message and records pause/resume reasons in the audit log
Consent and Do-Not-Contact Enforcement
Given a client has no recorded consent for SMS or has a Do-Not-Contact flag When a GapPrompt send is attempted Then the send is blocked, no message is transmitted, and the event is logged with the specific policy reason Given a client opts out via standard keywords (e.g., STOP) or via portal preferences When processing the message Then the channel is immediately set to Opted Out, all future automated sends are canceled, and a confirmation is not sent unless legally permitted Given a client reconsents via compliant flow When updating consent status Then automated messaging eligibility is restored and future sends follow all cadence and time-window rules
Identity Disambiguation Micro‑Flow
"As a paralegal, I want the system to disambiguate clients with similar names via quick prompts so that conflict checks are accurate without back‑and‑forth calls."
Description

Runs a targeted prompt sequence to distinguish between individuals with similar names or overlapping attributes detected by the conflict engine or CRM dedupe rules. Requests disambiguators such as full legal name (with middle), date of birth, last‑4 of phone, or prior address in small, sequential steps, stopping as soon as uniqueness is achieved. Confirms the selected contact record, updates conflict screening inputs, and records evidence of verification and user-provided disambiguators in the audit log.

Acceptance Criteria
Trigger and Sequential Disambiguation Flow
Given the conflict engine returns 2 or more candidate contacts for an intake When the micro-flow starts Then the system sends a first prompt requesting the full legal name including middle name Given the user replies with a disambiguator value When validating the input Then the system enforces format rules (e.g., DOB = YYYY-MM-DD, last-4 = 4 digits) and reprompts with an example if invalid Given uniqueness is not yet achieved after evaluating the latest input When continuing the sequence Then the system requests additional disambiguators in order: date of birth, last-4 phone digits, prior address, stopping after each step if a single candidate remains or confidence >= the configured threshold Given uniqueness is achieved When the selected contact summary is presented Then the user can confirm Yes or No; on Yes the flow ends, on No the flow continues to the next available disambiguator or escalates if none remain Given no reply within the configured response window When the window elapses Then exactly one reminder is sent; if still no reply after the reminder window, the flow escalates and stops sending prompts
Confirmation and System Updates
Given the user confirms the selected contact When confirmation is received Then the intake is linked to that contact, conflict screening inputs are updated, and the conflict engine re-screens using the new data Given system updates succeed When the re-screen completes Then the micro-flow status is set to Completed and no further prompts are sent Given any update fails When the retry policy executes (up to 3 attempts) Then errors are logged and a manual review task is created without creating duplicate contact records; the flow does not send additional prompts Given duplicate replies are received (e.g., user resends the same DOB) When processing repeated inputs Then updates are idempotent and do not create additional changes or duplicate audit entries
Audit Log and Evidence Capture
Given any prompt is sent or reply received When the event occurs Then an immutable audit entry is written with timestamp, channel, actor, template ID, masked PII values, and disambiguators used Given the user confirms identity When the flow completes Then the audit log includes the verification outcome, final matched contact ID, fields contributing to uniqueness, and a checksum of the transcript; all entries are queryable by matter ID Given an authorized administrator requests the audit record When access control is verified Then the masked transcript and event timeline are retrievable within 2 seconds for 95% of requests
Quiet Hours and Scheduling
Given current local time is within configured quiet hours When a prompt would be sent Then the message is deferred to the next allowed send time and no outbound messages are sent during quiet hours Given the user replies during quiet hours When processing the reply Then an auto-acknowledgement is queued if permitted and the next outbound prompt is scheduled for the earliest allowed time Given quiet hours configuration changes When the next message is scheduled Then the schedule respects the updated configuration without sending duplicate prompts
Language and Tone Adaptation
Given the contact’s preferred language is known When sending prompts Then messages are delivered in that language with a professional, empathetic tone and plain language at or below grade 8 readability Given the preferred language is unknown When the first reply is received Then the system detects language and switches subsequent prompts accordingly; if detection confidence is low, the message includes a language selection option Given a request for sensitive data When composing the prompt Then the message requests only the minimum necessary (e.g., last 4 digits) and includes a brief purpose statement
Delivery Failures and Escalation
Given an outbound SMS fails due to carrier error or opt-out When the failure is detected Then the channel is marked undeliverable and an authorized fallback channel (e.g., email) is attempted once; if no fallback is available, a manual task is created Given the maximum number of prompts (configurable, default 4) is reached without achieving uniqueness When the limit is hit Then the flow terminates and creates a manual review task with a summary of disambiguators collected and remaining ambiguity Given any escalation occurs When the task is created Then the intake is paused and the user is notified that a team member will follow up; no further automated prompts are sent
Attorney‑Configurable Templates & Rules
"As a solo attorney, I want to tailor micro‑prompt wording and rules to my practice so that the questions fit my process and local requirements."
Description

Provides a no‑code editor for attorneys to author versioned micro‑prompt templates with variables, conditional sections, and validation hints. Enables rule configuration for when prompts should trigger (by practice area, jurisdiction, intake stage, field conditions) and how responses map to structured fields. Includes preview with sample matters, test‑send, approval workflow, and rollback, plus a starter library aligned to common family‑law scenarios.

Acceptance Criteria
Author and Version a Template with Variables, Conditionals, and Validation Hints
Given I have Editor permissions, When I create a new micro-prompt template named "Child DOB Clarification", Then I can insert variables {{child.first_name}} and {{child.dob}} and attach a validation hint "Format: YYYY-MM-DD" and save as Version 1.0 with timestamp and change summary. Given the template includes a conditional section that renders when child.dob is empty, When I preview with a sample matter where child.dob is empty, Then the conditional section appears; When child.dob is present, Then the section is omitted. Given the available variable schema, When I reference an unknown variable {{child.middle_initials}}, Then Save is blocked and an error lists the unknown token(s). When I edit and Save New Version, Then Version 1.1 is created, Version 1.0 remains read-only, and a version diff is viewable showing added/removed lines. Given a regex ^\d{4}-\d{2}-\d{2}$ is set for child.dob, When I run a preview input check with "09/10/2018", Then the system flags it invalid and displays the hint "Use YYYY-MM-DD".
Configure Trigger Rules by Practice Area, Jurisdiction, Intake Stage, and Field Conditions
Given a rule: practice_area = Family Law, jurisdiction IN [CA,NV], intake_stage = "Conflict Screening", condition client.middle_name IS EMPTY, When a matter meets all conditions, Then the template is eligible and appears in the matter's Pending Prompts queue. When any listed condition is not met, Then the template is not eligible and will not be queued. Given two templates match simultaneously, When both are eligible, Then priority order is respected (lower number sends first) and simultaneous sends are prevented; And a log records which template fired and why. Given a rule is marked "fire once per matter", When the same gap persists after a response cycle, Then the template does not re-trigger unless manually re-armed.
Map Responses to Structured Fields with Type Validation and Audit Log
Given variable child.dob maps to Matter.Children[n].DOB (date), When a client replies "2012-03-09", Then the matter field is updated in ISO format with author=client, source=GapPrompt, and timestamp recorded. When a reply cannot be parsed to the target field type, Then the value is not saved, a re-prompt is queued using the validation hint, and the mapping result logs "Failed: type mismatch". Given multiple children records, When the prompt includes disambiguation (e.g., child.first_name or child.index), Then the mapping updates the correct child record only. When duplicate responses arrive, Then mapping is idempotent and retains the latest by timestamp while preserving an audit trail of prior values.
Preview Templates with Sample Matters Showing Conditional Rendering
Given a sample matter is selected, When I click Preview, Then I see the exact outbound text with variable substitution and conditional sections evaluated for that sample. When a variable has no sample value, Then a placeholder with the variable name and its validation hint is shown. Preview actions must not send any message or create matter activity; a visible "Preview Only" badge is displayed during preview.
Test-Send a Prompt Safely and Observe Delivery/Reply in Sandbox
Given I enter a verified test phone or email in the Test-Send modal, When I click Send, Then the message is delivered via sandbox channel, labeled TEST, and is not attached to any production matter timeline. When a reply is received to the test message, Then it appears in the Test-Send thread within 60 seconds and shows a simulated mapping outcome (e.g., "Would update: Children[0].DOB = 2012-03-09") without changing production data. When quiet hours are enabled for the account and the current time is outside the allowed window, Then Test-Send is blocked with an explanatory message and a Schedule option.
Approval Workflow Enforces Draft → Pending → Approved and Rollback
Given workflow states Draft, Pending Approval, Approved, Archived, When a template is Draft, Then it cannot be triggered by rules or test-sent. When a template is submitted for approval, Then only users with Reviewer role can Approve or Reject and must enter a change summary. When a template version is Approved, Then only that approved version is eligible to trigger; newer Draft/Pending versions are ignored at runtime. Given v1.2 is Approved and v1.3 is later Approved, When I Rollback to v1.2, Then v1.2 becomes the active Approved version and v1.3 is moved to Archived with a complete audit log (who, when, why).
Starter Library: Clone and Customize Family-Law Templates
Given the starter library is available, When an attorney selects "CA Parenting Plan: Child DOB Collection", Then they can clone it into their workspace as Draft, retaining variables, conditionals, and mappings. When a template is cloned, Then the clone is fully editable while the library original remains read-only. The library includes at least 15 family-law templates covering common gaps (e.g., child birthdates, prior case numbers, service addresses), each tagged with relevant jurisdictions and default trigger rules. When the firm's jurisdiction settings are configured, Then the library UI prioritizes templates matching those jurisdictions in search and recommendations.
Delivery, Tracking & Fallback Channels
"As an operations manager, I want reliable delivery and visibility into completion so that we can intervene only when needed."
Description

Integrates with SMS providers to send prompts with delivery receipts, carrier error handling, and unique short links for secure mini‑forms when multi‑field input is needed. Tracks opens, link clicks, and completion status, updating intake progress in real time. Implements retry strategies and automatic fallback to email or voicemail drop when SMS fails or the client has opted out, while deduplicating outreach across channels and notifying staff of exceptions requiring manual follow‑up.

Acceptance Criteria
SMS Delivery Receipts and Carrier Error Handling
Given a valid client mobile number and a queued GapPrompt When the system submits the message to the SMS provider Then a provider message ID is stored and message status = "Queued" within 1 second Given a queued SMS When the provider returns a delivery receipt webhook Then the message status updates to "Delivered" with carrier, timestamp, and provider ID within 5 seconds of receipt Given a provider error (e.g., undeliverable, rejected, unknown subscriber) When the error webhook is received Then the message status updates to "Failed" with a normalized error code and reason; hard failures are marked non-retriable; soft failures are marked retriable Given system logging When send or webhook events are recorded Then message body content is not persisted in error logs; only redacted tokens and metadata are stored
Secure Short Links & Mini-Form Tracking
Given a prompt requires multi-field input When composing the outbound message Then a unique HTTPS short link with a single-use token (TTL configurable, default 24h) is generated and embedded Given the short link is clicked When the mini-form loads Then click is recorded with timestamp and device metadata, and the form renders only the requested fields with any known values prefilled Given the form is submitted with valid data When processing completes Then intake fields are updated, the prompt status = "Completed", and the token is immediately invalidated Given an expired or previously used token When the link is accessed Then an "Expired/Invalid link" page is shown and no client data is exposed
Retry Strategy with Time-Window Respect
Given a transient send failure (e.g., timeout, retriable provider error, no receipt after threshold) When retries are enabled Then up to 3 retries are scheduled with exponential backoff (e.g., 5m, 30m, 2h) and capped by a max retry window Given the client's timezone and quiet hours configuration When scheduling retries Then no retry is sent outside allowed contact hours; the next attempt is deferred to the earliest allowed time Given any retry attempt succeeds When a delivery receipt arrives Then remaining retries are canceled and final status = "Delivered" Given all retries are exhausted without success When the final retry fails or times out Then status = "Failed-RetryExhausted" and channel fallback is initiated
Automatic Fallback to Email with Deduplication
Given SMS fails with a hard error or the client has opted out of SMS When a verified email address exists Then an email prompt with equivalent content and a valid tokenized link is sent within 2 minutes, and channel = "Email" is recorded Given a fallback email is sent When monitoring outreach Then deduplication ensures only one active prompt exists per request; duplicate sends across channels are prevented Given email engagement events (delivery, open if available, link click) When received Then the intake prompt status and timeline update accordingly; completion via email cancels any pending SMS retries Given both SMS and email fail or are unavailable When fallback cannot be completed Then an exception = "Escalate-FallbackFailed" is created for staff review
Voicemail Drop Fallback and Logging
Given SMS and email are unavailable or have failed and voicemail fallback is enabled When the client number is dialable and supports voicemail Then an automated voicemail is dropped within allowed contact hours containing a callback or short link reference, and the attempt occurs within 15 minutes of fallback initiation Given a voicemail drop attempt When the call concludes Then the system logs disposition (left voicemail/no mailbox/busy), recording URL, timestamp, and duration Given two unsuccessful voicemail attempts When the second attempt fails to leave a voicemail Then an exception task "AssignToStaff" is created with context for manual follow-up
Real-Time Progress Updates and Staff Notifications
Given delivery, click, completion, opt-out, or failure events occur When the event is ingested Then the intake record updates and the UI reflects the new status within 2 seconds; a timeline entry is appended with event type and timestamp Given an exception condition (hard failure, fallback exhausted, no reachable channel, or legal opt-out) When detected Then a staff notification is issued with client name, matter ID, channel history, last event, and a recommended next action Given a staff notification is issued When auditing Then an immutable audit log entry is written with who/when/context and linked to the intake and communication records
Channel State Deduplication and Idempotency
Given multiple processes attempt to send the same prompt concurrently When evaluated with an idempotency key Then exactly one outbound message is created; subsequent attempts are no-ops that return the original message ID Given a message is re-queued due to a transient error When processing resumes Then no duplicate client outreach occurs; the original message record is updated in place Given cross-channel fallbacks are in progress When the client completes the prompt via any channel Then all other active channel attempts for that prompt are canceled within 10 seconds and marked "Canceled-CompletedElsewhere"
Compliance, Consent & Audit Trail
"As a firm owner, I want all client messaging to be compliant and auditable so that we reduce risk and can prove our practices."
Description

Manages opt‑in/opt‑out consent per channel with keyword handling (STOP/START/HELP) and embeds jurisdiction-aware disclosures (TCPA/CASL/GDPR) in initial contact. Applies retention policies and redaction rules for sensitive fields, and propagates unsubscribe across related matters. Maintains an immutable audit trail of messages, content versions, consents, field updates, and send decisions, with export capabilities for discovery and regulatory inquiries.

Acceptance Criteria
SMS Opt-In/Opt-Out with STOP/START/HELP
Given a new contact with SMS channel enabled and a US phone number When the initial SMS is sent Then the message includes TCPA-compliant disclosure, business name, and clear STOP and HELP instructions Given any inbound SMS matching STOP (case-insensitive, punctuation/whitespace tolerated) When the message is received Then SMS consent is set to Opted-Out for that contact, a confirmation SMS is sent, further SMS are blocked, and an audit event with timestamp, channel, and content hash is recorded Given an Opted-Out contact When inbound START or UNSTOP is received Then SMS consent is set to Opted-In with timestamp, a confirmation SMS is sent, and an audit event is recorded Given any inbound HELP When received Then a HELP response including contact methods and unsubscribe instructions is sent and an audit event is recorded Given an Opted-Out contact When a workflow attempts to send an SMS Then the send is prevented, the decision cites consent status, and the decision is recorded in the audit trail
Email Unsubscribe and Resubscribe Flow
Given a new contact with email channel enabled and Canada jurisdiction When the initial email is sent Then the email includes CASL-compliant identification, purpose, and an unsubscribe link Given a recipient clicks the unsubscribe link When the request is confirmed Then email consent is set to Opted-Out for that contact, a confirmation page is shown, all future emails are blocked, and an audit event is recorded Given an Opted-Out contact When they use a resubscribe link or portal toggle with explicit consent checkbox Then email consent is set to Opted-In with timestamp and an audit event is recorded Given a scheduled email for an Opted-Out contact When the job runs Then the email is not sent, the job result indicates "Skipped: Opted-Out", and the decision is logged
Jurisdiction-Aware Disclosures Injection
Given a contact’s jurisdiction is US When sending the initial SMS Then a TCPA disclosure template is injected before the message body and recorded in the audit trail by template version and hash Given a contact’s jurisdiction is Canada When sending the initial email or SMS Then a CASL disclosure and identification details are injected and recorded by template version and hash Given a contact’s jurisdiction is EU or UK When sending the initial message on any channel Then GDPR disclosure including data controller identity and rights notice is injected and recorded by template version and hash Given the jurisdiction is unknown or ambiguous When attempting first contact Then the system applies the most conservative disclosure set and flags the record for jurisdiction confirmation Given bilingual preference is set to Spanish When injecting disclosures Then the disclosure is rendered in Spanish using the approved translation set and recorded
Retention Policy Enforcement and Sensitive Field Redaction
Given a matter is closed and 365 days have elapsed per policy When the nightly retention job runs Then messages and audit artifacts older than policy thresholds are purged or redacted per field category, and each action is logged with reason, actor=system, and counts Given a user without sensitive-data clearance views a transcript containing SSN, full DOB, or minors’ names When the transcript loads Then those fields are masked in UI and exports, and an access event is recorded Given an export request includes records with redacted fields When the export is generated Then redactions persist unless the requester has override privileges, and the export manifest indicates which fields were redacted Given a retention policy configuration is updated When saved Then the new policy version, scope, and effective date are recorded in the audit trail
Unsubscribe Propagation Across Related Matters
Given a client opts out of SMS or email on any matter When the opt-out is recorded Then the same channel is marked Opted-Out across all active and future matters linked to the client’s canonical identity (verified email/phone), and an audit event lists affected matter IDs Given a contact has multiple phone numbers or emails When opt-out occurs Then only the matching identifier is opted out unless policy is set to propagate across identifiers, in which case all verified identifiers are opted out and logged Given propagation completes When any related matter attempts to send via the opted-out channel Then the send is blocked and the decision cites the originating opt-out event
Immutable Audit Trail and Export for Discovery
Given any message send, consent change, field update, disclosure injection, or blocked send decision When the event occurs Then an append-only audit record is created with event type, actor, ISO-8601 timestamp with timezone, channel, jurisdiction, content/template hash, and previous-hash to ensure tamper-evidence Given an administrator requests an export for a specified client or matter and date range When processed Then the system produces a ZIP containing JSON or CSV audit records, message bodies, template versions, a hash manifest, and a human-readable summary PDF, filterable by channel and jurisdiction Given an export is generated When completed Then the action is logged with requester identity, scope, and checksum; exports containing unredacted sensitive data require elevated role and dual confirmation Given any attempt to alter or delete an existing audit record When executed Then the operation is rejected and the attempt is logged as a security event

CourtPack AutoBuild

As soon as required fields are in, assembles the correct jurisdiction‑specific packet: selects the right forms, merges extracted facts, inserts county‑level clauses, and calculates fees. Delivers a mobile preview for one‑tap attorney approval so filings move from chat to court‑ready fast.

Requirements

Jurisdiction Detection & Matter Routing
"As a solo family-law attorney, I want the system to automatically determine the correct court and venue from my intake so that the right packet is assembled without research or rework."
Description

Determines the correct jurisdiction (state, county, court division) and matter subtype from intake data, then gates AutoBuild until a minimum data threshold is met. Normalizes location inputs, validates residency and venue rules, and emits a readiness signal to trigger packet assembly. Integrates with CaseSpark intake workflows and conflict screening, preventing duplicate matters and ensuring the downstream rules engine receives consistent, validated context.

Acceptance Criteria
Jurisdiction Determination from Mixed Location Inputs
Given an intake with any combination of free-text city, ZIP/postal code, and county plus a selected matter subtype When jurisdiction detection is executed Then the system produces exactly one normalized jurisdiction tuple {stateCode, countyName, courtDivision} based on address geocoding and subtype mapping, and persists the normalized codes to the matter record
Gate AutoBuild Until Minimum Data Set Is Valid
Given a new matter with one or more required fields missing or invalid (clientFullName; opposingPartyName if subtype requires; matterSubtype; primaryAddress; state; county or resolvable ZIP; residencyDurationInState if rules require) When jurisdiction detection runs Then readiness=false and the system returns the list of missing/invalid fields Given a matter where all required fields are present and validated When jurisdiction detection runs Then readiness=true and a single readiness signal is emitted
Validate Residency and Venue Rules by Jurisdiction and Subtype
Given configured residency and venue rules for the selected jurisdiction and matter subtype When the provided residency duration or venue location does not satisfy those rules Then readiness=false and the specific failing ruleId and field(s) are returned Given inputs satisfy all configured residency and venue rules When jurisdiction detection runs Then readiness remains true
Prevent Duplicate Matters and Coordinate with Conflict Screening
Given a new intake matches an existing open matter by normalized party identifiers, matter subtype, and jurisdiction When jurisdiction detection runs Then a duplicate is flagged, automatic matter creation/routing is blocked, and readiness is not emitted Given conflict screening status is not 'Cleared' When jurisdiction detection runs Then readiness=false with reason='ConflictNotCleared' Given conflict screening status is 'Cleared' and no duplicate exists When jurisdiction detection runs Then detection proceeds to readiness evaluation
Resolve Ambiguous or Incomplete Location Inputs
Given inputs map to multiple possible counties or court divisions When jurisdiction detection runs Then status='AmbiguousLocation' is returned with ranked options for disambiguation and readiness=false until selection is made Given the user selects one of the returned options When jurisdiction detection re-runs Then a single jurisdiction tuple is set and readiness evaluation continues
Emit Readiness Signal with Validated Context for Rules Engine
Given all validations pass When readiness=true Then an event 'JurisdictionContext.Ready' is emitted within 1 second containing stateCode, countyCode, courtDivisionCode, matterSubtypeCode, normalizedAddress, appliedRuleIds, deduplicationId, and validationSummary='Pass', and AutoBuild is triggered Given readiness changes from true to false due to updated inputs When jurisdiction detection runs Then an event 'JurisdictionContext.NotReady' is emitted within 1 second and AutoBuild is not triggered or is cancelled if pending
Performance and Audit Trace for Detection and Routing
Given valid inputs When jurisdiction detection runs Then P95 latency is <= 500 ms for US addresses using cached references, and the decision rationale (input snapshot, normalization outputs, ruleIds applied, conflict/duplicate checks, final readiness status) is written to an immutable audit log associated with the matterId
Rules-Driven Form Set Selection
"As an attorney, I want CaseSpark to auto-select the correct jurisdiction-specific forms so that I don’t miss required documents or include unnecessary ones."
Description

Selects the exact form packet required for the identified jurisdiction and matter type using a versioned, testable rules engine. Supports effective-dated rule changes, county overrides, edge-case inclusions (e.g., minor children, default service), and required attachments (exhibits, cover sheets). Falls back gracefully with actionable prompts when inputs are incomplete. Integrates with the template library and maintains audit logs of rule versions applied for defensibility.

Acceptance Criteria
Primary Form Packet Selection by Jurisdiction and Matter Type
- Given intake contains Jurisdiction, County, and Matter Type fields completed - When the rules engine evaluates the tuple (Jurisdiction, County, Matter Type) - Then it returns exactly one packet ID and the ordered list of form template IDs defined for that rule - And no additional forms outside the rule are included - And each selected form is sourced from the template library with the specified template version - And the engine response time is <= 500 ms at the 95th percentile across 1,000 selection requests
Effective-Dated Rule Application and Version Lock
- Given two rule versions for the same tuple with non-overlapping effective date ranges - When assembly is triggered with an assembly timestamp within range A - Then version A is selected and recorded - When assembly is triggered with an assembly timestamp within range B - Then version B is selected and recorded - And once a version is applied to a matter, subsequent rule changes do not alter the stored version for that matter - And backdated assemblies use the effective version matching the supplied as-of date
County-Level Overrides and Clause Insertion
- Given a state-level rule and a county-level override for the same tuple - When evaluation runs for that county - Then county-specific form variants and clause blocks replace or augment the state-level items as defined - And if no county override exists, the state-level rule is used - And only one override layer is applied (no duplicate forms from both layers) - And the county-specific template versions are fetched from the template library successfully
Edge-Case Conditional Form Inclusions
- Given flags such as hasMinorChildren, defaultService, or expeditedRelief collected during intake - When evaluation runs - Then conditional forms and attachments associated with each true flag are added to the packet - And mutually exclusive options resolve to the higher-priority rule as defined in the rule set - And no duplicate forms are added when multiple flags map to the same document - And all conditional inclusions are reflected in the packet manifest
Required Attachments and Cover Sheets Assembly
- Given the selected packet requires exhibits, cover sheets, or proof-of-service attachments - When the packet is assembled - Then required attachments are included with correct ordering and naming conventions per rule - And the correct jurisdiction/county cover sheet template version is used from the template library - And placeholders are generated for any required attachment content not yet provided, labeled with the missing fields - And the packet manifest lists every attachment with template ID and version
Graceful Fallback with Actionable Prompts on Missing Inputs
- Given one or more required inputs for packet selection are missing (e.g., Jurisdiction or Matter Type) - When evaluation is attempted - Then packet assembly is not executed and no partial packet is produced - And the user is shown an actionable list of missing fields with friendly labels and deep links to collect them - And the system proposes the minimum next questions needed to disambiguate the packet when applicable - And an audit event is logged for the failed attempt without erroring the session
Audit Logging of Rules Applied for Defensibility
- Given a packet selection or assembly occurs - When the process completes successfully or fails gracefully - Then an immutable audit record is written containing matter ID, user ID, timestamp, rule engine version, rule set IDs evaluated, selected rule IDs, condition flags, and template version IDs - And the record is viewable and exportable as JSON via the admin console - And subsequent rule updates do not modify historical audit entries - And the audit entry includes a checksum or signature to detect tampering
Dynamic Field Mapping & Data Merge
"As a practitioner, I want client answers merged accurately into every form so that the packet is complete and compliant without manual edits."
Description

Maps normalized intake data to form fields and narrative sections, handling conditional fields, computed values (age, residency duration, fee totals), and jurisdiction-specific phrasing. Ensures proper formatting (names, addresses, dates, monetary values), supports multi-child repeating sections, and applies redaction rules where required. Provides validation feedback and highlights missing or inconsistent data before preview generation.

Acceptance Criteria
Conditional Field Mapping by Jurisdiction and Case Type
Given normalized intake data includes jurisdiction, county, and case type When form fields are mapped for packet assembly Then only fields required for the selected jurisdiction/county and case type are included in the merge And conditional sections render only when their predicates evaluate true And optional unmapped fields remain absent (not rendered as blanks or placeholders) And required-but-missing jurisdictional fields are flagged with field-level identifiers before preview is enabled And hidden or inapplicable fields do not appear in the preview or output artifacts
Computed Values: Age, Residency Duration, and Fee Totals
Given a filer’s date of birth and filing date When age is computed Then age in years equals the correct value as of the filing date, including leap-day DOB handling on non-leap years Given a residency start date and the filing jurisdiction’s threshold rule (e.g., 6 months, 90 days) When residency duration is computed Then the duration reflects whole units per rule and correctly passes/blocks the threshold on boundary dates Given base filing fees, county surcharges, per-party/per-child add-ons, and waivers/credits When fee totals are computed Then the grand total equals the sum of applicable components with 2-decimal precision and jurisdiction rounding rules And a line-item breakdown is available for audit with component IDs
Jurisdiction- and County-Specific Phrasing and Clauses
Given the selected jurisdiction and county When generating narrative sections and clauses Then the system selects the correct template variants by template ID and locale And inserts required county-level clauses in the appropriate sections And uses correct party labels (Petitioner/Respondent or equivalents) and pronouns throughout And applies singular/plural and child/children grammar rules based on data cardinality And no unresolved tokens or placeholders (e.g., {{name}}) appear in the output
Data Formatting: Names, Addresses, Dates, Monetary Values
Given normalized names including prefixes/suffixes and middle names/initials When merged Then names are formatted as court-style "First M. Last, Suffix" with correct capitalization rules Given postal addresses When merged Then addresses are normalized to jurisdiction-approved format (street, unit, city, state/province, postal code), with state/province abbreviations as required Given dates When merged Then dates appear in the jurisdiction-required format (e.g., MM/DD/YYYY) with zero-padding and correct timezone-normalized day where applicable Given monetary fields When merged Then values include currency symbol where required and 2 decimal places, with thousands separators per locale
Multi-Child Repeating Sections Across Forms
Given N children are recorded in intake When mapping to forms that require repeating child sections Then exactly N repeat sections are generated in order across all relevant forms And child indices/anchors are consistent across forms and narratives And missing required child fields are flagged with child index and field name prior to preview And no orphaned or duplicate child sections appear in the output
Mandatory Redaction Rules in Previews and Outputs
Given fields designated as sensitive by jurisdictional redaction rules (e.g., SSN, full DOB for minors, contact info in protected-address cases) When generating previews and output artifacts Then those fields are redacted per rule (masking pattern or removal) in all outputs where redaction is required And the redacted output does not contain extractable underlying text for those fields (content removed, not just visually obscured) And internal-only copies retain full data as configured and are clearly labeled And a redaction audit list is produced with field IDs and applied rule references
Pre-Preview Validation Feedback for Missing/Inconsistent Data
Given intake data is incomplete or inconsistent When validation runs prior to preview generation Then the system displays field-level inline errors and a summary panel listing all blocking issues with field IDs And cross-field checks (e.g., county inconsistent with state, residency threshold unmet, fee sum mismatch) are identified with precise messages And preview and approval actions remain disabled until all blocking validations pass And upon resolution, validations re-run automatically and the preview becomes enabled
County Clause Library & Conditional Inserts
"As a family-law attorney, I want county-specific clauses inserted automatically so that filings reflect local rules without me keeping a personal clause bank."
Description

Maintains a versioned library of county-level clauses and instructions, inserting them into pleadings and captions based on court-specific requirements. Supports conditions (e.g., service method, domestic violence considerations), variable placeholders, and effective dates. Includes admin tools for legal ops to update clauses safely with review workflows, and logs which clause versions were applied for each packet.

Acceptance Criteria
Auto-insert County-Specific Clauses into Pleadings and Captions
Given a packet is assembled for a matter with known county, court, and filing type And jurisdictional clause mappings exist for the selected forms When packet assembly runs Then the system inserts the mapped county-level clauses into the correct document sections (caption, body, footer) for each form And the inserted clause text exactly matches the approved version content (no truncation; whitespace preserved) And the ordering of multiple clauses respects the defined priority indices And the assembly completes without missing-required-clause errors
Conditional Inserts Based on Service Method and DV Flag
Given conditional rules exist referencing attributes such as service_method, dv_flag, interpreter_needed And the matter has service_method = "personal" and dv_flag = true When packet assembly runs Then only clauses whose conditions evaluate to true are inserted And clauses with mutually exclusive conditions are excluded And rule evaluation supports AND/OR with explicit precedence and parentheses And condition evaluation outcomes are recorded per clause in the packet audit
Variable Placeholder Resolution and Validation
Given a clause contains placeholders like {{petitioner_full_name}}, {{respondent_full_name}}, {{county_name}}, {{hearing_date | date:MM/DD/YYYY}}, and {{case_number?}} And corresponding data exist in the intake record where required When the clause is rendered Then all placeholders are replaced with correctly formatted values per directives And any missing required placeholder halts assembly with a descriptive error listing the missing fields And optional placeholders with defaults render the default values And a placeholder-to-value substitution map is stored in the packet audit (with PII redaction per policy)
Effective Date Version Selection for County Clauses
Given a clause has multiple versions with non-overlapping effective date ranges and publish timestamps And the packet has a filing date/time set When selecting which clause version to apply Then the version whose effective range includes the filing date in the court's local time zone is used And backdated filings select the historically correct version And future-dated filings select a future-effective version only if configuration allows; otherwise use the latest current version And the chosen version and selection rationale are recorded in the packet audit
Auditability of Applied Clause Versions
Given packet assembly completes When viewing the packet audit log Then for each inserted clause the log includes: clause_id, clause_title, version_id, effective_range, condition_results, placeholder_substitutions (redacted as configured), timestamp, and assembler build/version And the audit log is immutable and accessible via UI and API within 2 seconds for packets with up to 50 clauses And the audit supports export to PDF and CSV listing clause titles and versions applied
Admin Review Workflow for Safe Clause Updates
Given a Legal Ops Draft Editor creates or edits a county clause When they save changes Then the clause is stored as a draft and is not available to assembly until approved And a Reviewer can request changes with comments; the Editor can revise and resubmit And an Approver publishes the draft, creating an immutable version with an effective start date/time And role-based permissions prevent non-Approvers from publishing And previously published versions remain viewable; rollback creates a new superseding version And a redline diff view highlights changes between versions at word and line levels
Fallback Handling When County Mapping Is Missing
Given a packet targets a county/court/form section with no mapped clause or only expired versions When packet assembly runs Then if a state-level default clause is configured, it is inserted and flagged as default-sourced in the audit and preview And if no default exists, assembly halts pre-approval with an error naming the missing county, court, form, and section And an alert is sent to Legal Ops with a link to create the missing clause; the event is logged for SLA tracking
Court Fee Calculator & Waiver Handling
"As an attorney, I want accurate, up-to-date fee totals included with the packet so that I can advise clients and file without surprises."
Description

Calculates filing fees for the selected court, including surcharges, e-filing vendor fees, and service-of-process costs. Accounts for fee waivers, indigency affidavits, and county-specific exceptions, outputting a clear cost summary in the preview. Supports scheduled updates to fee tables with effective dates and provides alerts when fee schedules change.

Acceptance Criteria
Jurisdiction and Case-Type Fee Calculation
Given a jurisdiction, court, case type, and filing method are selected And an effective fee schedule exists for the intended filing date When the calculator runs Then base filing fees for the selected jurisdiction/case type are included And applicable surcharges for the filing method are included And e-filing vendor fees are included when filing method is e-file And selected service-of-process costs are included when service is requested And an itemized list shows each line with label and amount And the total equals the sum of all included line items to the cent
Fee Waiver and Indigency Affidavit Application
Given the client is marked fee-waiver eligible and an indigency affidavit is captured And the jurisdiction defines waivable vs non-waivable fees When the calculator runs Then all waivable fees are set to $0.00 and labeled "Waived" And non-waivable fees remain at full amount And the total equals the sum of non-waivable fees only And the preview displays a waiver note referencing the affidavit
County-Specific Fee Exceptions
Given a county is selected that defines overrides or additional county-level fees When the calculator runs Then county overrides replace standard fee amounts where rules apply And county additions are included as separate line items And exceptions apply only when their conditions (e.g., case sub-type, party count) are met And the total reflects overridden and additional amounts correctly
Effective-Dated Fee Tables Selection
Given multiple fee tables exist with effective start and end dates And the intended filing date is provided When the calculator runs Then the fee table whose effective period contains the filing date is used And if no filing date is provided, the current date is used And the preview displays "Fees effective as of {date}" matching the selected table And if a table change is scheduled within 30 days of the filing date, an informational note is shown
Fee Schedule Change Alerts
Given an administrator updates or imports a fee schedule When the change is saved Then an alert is generated within 15 minutes to subscribed users And the alert includes jurisdiction, affected courts, effective date, and count of changed items And active matters with filing dates in the affected period show an in-context warning on their cost preview And an audit log records who changed what with timestamps
Mobile Preview Cost Summary
Given the attorney opens the mobile preview on a standard smartphone When the cost summary renders Then itemized fees, waiver labels, and totals are visible without horizontal scrolling And currency is formatted per locale to two decimal places And the total due appears prominently above the fold And the preview loads within 2 seconds over a 4G connection for up to 20 fee line items And accessibility meets WCAG 2.1 AA for contrast and touch targets
Service-of-Process Cost Options
Given a service-of-process method (sheriff, private server, certified mail) is selected in intake When the calculator runs Then the corresponding cost for the selected method is included from the effective table And if no exact amount exists, an estimated range is displayed with an "Estimate" label And the preview indicates whether the cost is collected upfront or billed later per jurisdiction rules And changing the service method updates the line item and total in real time
Mobile Preview & One-Tap Approval
"As a solo attorney on the go, I want to preview and approve the packet on my phone with one tap so that I can move matters from intake to filing quickly."
Description

Generates a mobile-optimized packet preview with page-level navigation, inline validation alerts, and a fee breakdown. Supports track-changes style highlights since last build, watermarked previews, and a one-tap approval that locks the packet and records an audit trail. Offers quick-edit of key data points and a request-changes loop that regenerates the packet in seconds.

Acceptance Criteria
Mobile-Optimized Preview with Page-Level Navigation
Given a completed minimum-required intake and an auto-built packet When the attorney opens the preview on a mobile device (iOS Safari 16+ or Android Chrome 120+) with viewport width 320–430px Then the first page renders within 2 seconds and page-to-page navigation latency averages ≤200ms for packets up to 50 pages And text is legible at default zoom (minimum 14px body), tap targets are ≥44x44px, and horizontal scrolling is not required for content width And when the device is rotated, the preview reflows without layout breakage within 500ms and maintains the current page And under 750kbps bandwidth, a skeleton loader appears within 300ms and content resolves progressively
Inline Validation Alerts for Missing/Invalid Data
Given required fields are incomplete or invalid per the validation ruleset When the preview is opened Then an inline alert appears at each affected field/location and a persistent summary banner displays the total count and the first three issues And tapping a banner item scrolls and focuses the corresponding field within 300ms And while any blocking issues exist, the Approve button is disabled with an accessible rationale tooltip; once all blocking issues are resolved, the button enables within 200ms without page reload And each alert shows the field label, rule violated, and a fix hint; test cases produce zero false positives/negatives against the ruleset
Fee Breakdown Calculation and Display
Given the matter's jurisdiction, county, and filing type When viewing the fee breakdown in the preview Then line items include base filing fee, county surcharges, e-filing provider fee, optional service of process, and applicable taxes with clear labels and amounts And the total equals the sum of line items and matches the fee engine output for identical inputs within $0.01 And when county or filing type changes via Quick Edit, line items and total update within 1 second and display an "Updated" timestamp And currency formatting matches locale (USD $#,###.##) and an "Estimated" tag appears when fees are flagged as estimates
Track-Changes Highlights Since Last Build
Given at least two builds exist for the packet When viewing the current preview with Show changes enabled Then insertions are highlighted with green underline, deletions with red strikethrough, and modified fields with yellow background And a change summary lists counts of insertions, deletions, and modifications with page numbers; tapping an item jumps to the location within 300ms And toggling Show changes off removes all highlights without altering content; toggling on restores them And the diff output matches expected fixtures for test datasets (deterministic results)
Watermarked Pre-Approval Preview
Given the packet is not approved When viewing or exporting the preview Then each page displays a semi-transparent diagonal watermark reading "DRAFT — NOT FOR FILING" at 20–30% opacity that does not obscure form fields And after approval, the watermark is removed from the approved preview and any filing-ready PDFs And screenshots and PDF exports taken prior to approval retain the watermark And watermark rendering does not increase page render time by more than 10% compared to no watermark
One-Tap Approval: Locking and Audit Trail
Given all blocking validations pass When the attorney taps Approve and confirms Then the packet status updates to Approved within 1 second and content becomes read-only (no edits allowed without creating a new version) And an audit log entry is created capturing user ID, timestamp (UTC ISO-8601), client IP, packet version ID, SHA-256 checksum of the approved PDF, and a diff summary; the entry is immutable And attempting to modify an Approved packet shows a read-only notice and offers Request changes to create a new build And a confirmation banner displays success with actions to Send to e-filing and Download
Quick-Edit and Request-Changes Regeneration Loop
Given the preview is open When the attorney uses Quick Edit on key data points (party names, county, case type, hearing date, addresses) Then an inline editor opens without leaving the preview and validates inputs in place And upon save or submitting Request changes with notes, a new packet build generates within 5 seconds for packets up to 50 pages and the preview auto-refreshes to the new version And the updated data appears in all relevant fields, and Since last build highlights show the changed areas And the build version increments, the prior version remains accessible via version history, and the regeneration is recorded in the audit log with requester notes
Court-Ready Export & E-Filing Packaging
"As a practitioner, I want a properly packaged, court-compliant export so that I can file immediately without manual reformatting."
Description

Produces court-ready outputs: flattened and/or fillable PDFs per court rules, correct naming conventions, PDF/A where required, and a zip/envelope with required metadata for e-filing portals. Ensures signature fields are routed to e-sign if not already captured, embeds bookmarks and TOC if mandated, and saves artifacts to the matter record with immutable versioning.

Acceptance Criteria
Jurisdiction-Specific PDF Output Compliance
Given a matter has jurisdiction and court rules resolved from the court profile When export is initiated for court-ready outputs Then the system generates each document as flattened, fillable, or PDF/A per the rule mapping And the PDF/A conformance level matches the court profile (e.g., PDF/A-1b or PDF/A-2b) And all required fonts are embedded and form fields designated non-editable are flattened And the documents pass the built-in PDF compliance validator with zero errors And a compliance report artifact is generated and attached to the matter
E-Filing Envelope and Metadata Packaging
Given the target court requires an e-filing envelope/zip with a manifest When export is initiated Then the system creates a single zip/envelope containing all required PDFs And includes a manifest in the format specified by the court profile (JSON or XML) And the manifest contains required fields: courtLocation, caseType, filingCode, partyInfo, attorneyBarNumber, paymentAccount, fees, and a documentList with docType and securityLevel And all required metadata fields are validated as present and conforming to allowed values And the zip/envelope file name matches the court naming rule defined in the court profile And if any required metadata is missing or invalid, export is blocked and field-level validation errors are returned
Naming Convention Enforcement
Given naming rules are defined in the court profile for each document type When documents are generated for export Then each file name matches the rule’s regex pattern And file names do not exceed the maximum length specified by the rule And only allowed characters are used (e.g., A–Z, 0–9, underscore, hyphen) per rule And a YYYYMMDD date stamp is included where mandated And duplicate base names in a package are resolved by appending an incremental suffix without violating length or character rules
Signature Routing and Export Gating
Given documents requiring signatures are identified and signers are configured And one or more required signatures are missing When export is initiated Then the system creates an e-sign request per signer with name, email, role, and tagged signature fields And the matter export status is set to Pending Signatures And final e-filing packaging is prevented until all required signatures are completed And upon completion of all signatures, packaging resumes automatically and status updates to Ready for Filing And all e-sign events (sent, viewed, signed) are logged to the matter timeline
Court-Mandated Bookmarks and TOC
Given the court profile mandates bookmarks and/or a table of contents When generating a consolidated PDF for export Then top-level bookmarks are created for each primary document and attachment And nested bookmarks reflect section headers where available And a generated TOC page is inserted at the beginning with page numbers aligned to bookmarks And bookmark labels match document titles per the court profile And the bookmark/TOC validator reports zero missing or broken entries
Immutable Versioning and Matter Record Storage
Given export artifacts are produced When the package is finalized Then all PDFs, manifests, envelopes, and compliance reports are saved to the matter as a new immutable version And the version includes a monotonically increasing version number, timestamp, and SHA-256 checksum per artifact And stored artifacts are read-only and cannot be overwritten in place And an audit log entry records the user, trigger, template version, and environment And prior versions remain retrievable without alteration
Fee Metadata and Payment Readiness in Package
Given the filing requires fees per the court profile and a payment account is selected When building the export package Then the manifest includes totalFees and a feeBreakdown with fee codes and amounts And fees are calculated using the effective court fee schedule date from the profile And currency and rounding follow the court specification And if a fee waiver applies, the waiver document is included and fees are set to zero as permitted And packaging fails validation if a required payment account token is missing or expired

TapSign Link

Delivers a frictionless, mobile‑first signing session via secure SMS/WhatsApp link—no app or login required. Supports initials, signatures, and date stamps, and can pair with Sign‑to‑Pay for retainers. Returns signed PDFs instantly and updates matter status, accelerating conversion from text to e‑sign.

Requirements

Secure SMS/WhatsApp Link Delivery
"As an intake coordinator, I want to send clients a secure signing link by text so that they can sign immediately on their phones without creating an account."
Description

Generate single-use, tamper-resistant signing URLs and deliver them via SMS and WhatsApp with branded sender identity, opt-in/opt-out support, and per-jurisdiction consent language. Links are HMAC-signed, time-bound, and optionally protected by a one-time code. Delivery includes retry logic, rate limiting, and automatic fallback to email when messaging fails. All delivery events (sent, delivered, opened) are logged and associated to the matter for auditability and to trigger CaseSpark workflow steps.

Acceptance Criteria
Single-Use, HMAC-Signed, Time-Bound Link Generation
Given a matter with a designated signer and a request to create a TapSign link When the system generates the signing URL Then the URL contains an opaque, unguessable token with at least 128 bits of entropy And the token is HMAC-SHA256 signed with a server-held secret and includes an expiry timestamp And the configured TTL is applied (default 24h, configurable 15m–7d) And the URL contains no PII in path or query parameters Given a valid, unexpired, unused link When a client requests the link Then the server validates the HMAC signature and expiry before rendering the session Given a link that has been successfully opened once When any subsequent request is made using the same link Then the server returns HTTP 410 Gone and no signing session is rendered Given a link with a modified token or mismatched signature When the link is requested Then the server returns HTTP 401 Unauthorized and logs a tamper event Given any link creation event When logging occurs Then the audit log records link_id, signer_id (internal), matter_id, created_at, expires_at, ttl, and creator_id
Optional One-Time Code (OTP) Protection on Link Open
Given OTP protection is enabled for the signer When the signer opens a valid link Then the system sends a 6-digit OTP via the same channel used to deliver the link (SMS or WhatsApp) And the OTP expires in 10 minutes and is single-use And a maximum of 5 verification attempts are allowed before the link is locked for 30 minutes Given a correct OTP within the validity window When the signer submits the OTP Then access to the signing session is granted and the OTP is marked consumed Given an incorrect OTP or expired OTP When the signer submits the OTP Then access is denied with a non-revealing error message and remaining attempts are shown Given OTP send/verify events When logging occurs Then events include channel, attempt_count, success/failure, timestamp, sender_id/message_id where applicable, and are associated with the matter and signer
SMS Delivery with Branded Sender, Opt-In/Out, and Jurisdictional Consent
Given a signer with a mobile number and SMS channel selected When a TapSign link is sent via SMS Then the message is sent from the configured branded sender identity (alphanumeric where supported, fallback long/short code otherwise) And the message body includes per-jurisdiction consent language and opt-out instructions (e.g., “Reply STOP to opt out”) And the message includes only a short URL on the configured domain and does not expose PII Given the recipient has previously opted out of SMS for this tenant When a send is attempted Then the system blocks the send, records the block with reason=opted_out, and surfaces a user-visible error Given delivery receipts are supported by the carrier When the SMS is processed Then sent and delivered statuses are captured with timestamps and carrier message IDs and logged to the matter Given a recipient replies STOP When the MO message is received Then the system marks the phone number opted-out for SMS under the tenant and confirms opt-out via a single confirmation SMS where allowed by law
WhatsApp Delivery with Branded Business Profile and Consent
Given a signer with a WhatsApp-registered number and WhatsApp channel selected When a TapSign link is sent Then the message is sent from the verified WhatsApp Business profile with display name matching the tenant brand And an approved template is used including jurisdiction-appropriate consent language and the short URL Given the recipient has not provided WhatsApp opt-in When a send is attempted Then the system does not send the WhatsApp message, records reason=not_opted_in, and suggests alternate channels Given WhatsApp delivery and read receipts are available When the message is processed and viewed Then message sent/delivered/read events with WhatsApp message IDs and timestamps are captured and logged to the matter Given the recipient sends a Stop-equivalent message When the inbound message is received Then the number is marked opted-out for WhatsApp under the tenant and future sends are blocked
Retry Logic and Automatic Fallback to Email
Given a TapSign link send is initiated via a primary channel (SMS or WhatsApp) When a transient provider error occurs (e.g., 5xx, timeout) Then the system retries up to 3 times with exponential backoff (e.g., 1s, 5s, 20s) And retries stop immediately upon a definitive success receipt Given a permanent failure occurs (e.g., invalid number, blocked, opted_out) When the send fails Then no further retries are attempted on that channel and the failure reason is logged Given both SMS and WhatsApp are unavailable or have failed definitively When fallback_to_email is enabled and an email address exists Then the system sends a branded email containing the same TapSign link And records a fallback event linking the email message_id to the original attempt Given multiple channels and retries When logging occurs Then only one channel should reach a successful delivery state per attempt group and duplicate suppression is enforced
Rate Limiting and Throttling for Messaging and OTP
Given tenant-level default rate limits (configurable) When sending TapSign links Then enforce limits of max 3 link messages per recipient number per 30 minutes, max 5 per matter per day, and max 100 per tenant per hour And return a 429 Too Many Requests with retry-after seconds when limits are exceeded Given OTP requests for a link When the signer requests additional OTPs Then enforce max 3 OTP sends per 15 minutes per link and jittered delays between sends Given provider-level throughput constraints When bulk sends occur Then the system queues messages and releases them according to provider rate caps without loss or reordering within a matter Given any rate limit breach When logging occurs Then a throttling event with scope (recipient/matter/tenant), limit, current_count, window_start, and retry_after is recorded and visible in admin reporting
Delivery Event Logging, Auditability, and Workflow Triggers
Given any message lifecycle event (sent, delivered, read/opened) from SMS/WhatsApp/email When the event is received or inferred Then the system records an immutable audit entry with matter_id, signer_id (internal), channel, event_type, timestamp (UTC), provider_message_id, link_id, and source IP/user agent where available Given an “opened” event for a TapSign link When the audit entry is recorded Then the matter’s timeline is updated in real time and a workflow trigger “link_opened” is emitted within 2 seconds for downstream CaseSpark automations Given no open event is received within 24 hours of “sent” When the workflow scheduler runs Then a “remind_signer” task is queued (respecting rate limits and opt-out) and logged Given audit data retention policies When data exceeds the configured retention period (default 7 years) Then records are archived in a write-once store with verifiable checksums and remain queryable to authorized roles
Mobile-First Signing Session
"As a client on my phone, I want a simple signing flow I can complete in a few taps so that I can finish intake quickly without downloading an app or logging in."
Description

Present a responsive, app-free signing experience optimized for small screens with large tap targets, pinch-to-zoom, and progressive loading for multi-page documents. Support typed/drawn signatures, initials, and date stamps, plus checkbox and text fields with validation and required-field gating. Provide step-by-step guidance, progress indicators, auto-scroll to next field, and WCAG 2.1 AA accessibility. Sessions resume from the same link if interrupted and enforce inactivity timeouts to protect sensitive data.

Acceptance Criteria
One-Tap Link Launches App-Free Mobile Signing
Given a recipient receives a TapSign link via SMS or WhatsApp When the recipient taps the link on a mobile device without any app installed Then the signing session opens in the default mobile browser over HTTPS without requiring account login And the session URL is single-use tokenized and bound to the intended recipient And if the link is opened on a second device concurrently, the second device shows a non-revealing "Session already in use" message and no document content And if the link is reused after completion, the user sees "Document already signed" and no document content is exposed
Responsive UI and Large Tap Targets on Small Screens
Given a mobile device in portrait with a viewport width between 320 and 428 CSS pixels When the signing session loads Then all primary interactive controls (e.g., Next, Continue, Sign, Initial, Checkbox) have hit areas at least 44x44 CSS pixels And no horizontal scrolling is required to view or interact with form fields and toolbars And layout reflows correctly on orientation change within 500 ms without losing field focus or entered data And the session becomes interactive within 2.5 seconds on a typical 4G connection
Pinch-to-Zoom and Progressive Multi-Page Loading
Given a multi-page document (>= 10 pages) When the session opens Then the first page renders clearly within 2.5 seconds on a typical 4G connection And pinch-to-zoom is supported from 50% to 300% with panning, with gesture latency <= 100 ms And additional pages lazy-load when within one viewport of entering view and render within 800 ms each And a visual placeholder indicates pages are loading, preventing layout shift
Signature, Initials, and Date Stamp Inputs
Given a document containing signature, initials, and date fields When the signer taps a signature field Then they can choose Typed or Drawn input modes And Typed mode allows entering up to 60 characters and previews the signature in-place at field scale And Drawn mode captures touch input with undo and clear actions available And Initials fields support the same input modes and can auto-suggest initials from the typed name And Date fields marked as stamp auto-insert the current local date and are read-only And applied marks render at the correct coordinates in the final PDF without clipping or pixelation
Field Validation and Required-Field Gating
Given a document with required text and checkbox fields When a required field is empty or fails validation Then an inline error message is shown adjacent to the field and announced to assistive technology And the Continue/Finish action is disabled until all required fields pass validation And text fields enforce max length and pattern constraints (e.g., email) with clear, human-readable error messages And checkbox groups enforce minimum required selections when configured
Guided Flow with Progress Indicator and Auto-Scroll
Given there are uncompleted required fields When the signer taps Next Then the viewport auto-scrolls to the next required field with smooth focus placement above the on-screen keyboard And a visible progress indicator shows completed/total required fields and updates in real time And after the last required field is completed, the signer is taken to a Review screen with a prominent Finish action And the signer can navigate back without losing previously entered data
Session Resume via Same Link and Inactivity Timeout
Given a signing session in progress When the signer closes the browser or loses connectivity Then reopening the same TapSign link within 24 hours restores the session state and scroll position to the next required field And if there is no interaction for 10 minutes, a 60-second warning is shown, after which the session locks and hides document contents And after timeout, the signer must reopen the TapSign link to resume; no sensitive data remains visible in the browser history or screen And all resume and timeout events are captured in the audit log with timestamps
Identity Verification & Audit Trail
"As a managing attorney, I want a verifiable audit trail of who signed and when so that signatures stand up to scrutiny and reduce dispute risk."
Description

Capture and bind signer identity signals to the signing event, including verified delivery channel (phone number), optional SMS one-time code, IP address, device and browser metadata, timestamps, and geo-indicative data where permitted. Produce a tamper-evident audit log and embed an evidence summary with cryptographic hash of the final PDF. Store immutable event history in CaseSpark, support export of the audit report, and align with e-sign standards (e.g., E-SIGN/UETA) through explicit e-records consent acknowledgments.

Acceptance Criteria
SMS/WhatsApp Link Access with Optional OTP
Given a TapSign link is sent to a verified phone number in E.164 format via SMS or WhatsApp When the recipient opens the link Then the audit records the delivery channel (SMS or WhatsApp), phone number, message ID, and link ID Given OTP verification is enabled for the session When the recipient enters the correct one-time code within the configured validity window and attempt limit Then the session is unlocked and the audit records OTP verification success with timestamp And When the code is incorrect, expired, or the attempt limit is exceeded Then access is denied, rate limits are enforced, and each attempt and outcome is logged Given OTP verification is disabled for the session When the recipient opens the link Then the audit records that OTP was not required with the configured reason (policy or override) and the actor who configured it
Capture IP, Device, Browser, Timestamps, and Geo (Where Permitted)
Given a signer starts a TapSign session When the session initializes Then the system records server-side UTC timestamp, source IP address, user agent string, device type, OS, and browser version Given jurisdiction and user permissions allow location capture When the session initializes Then the system records geo-indicative data (at minimum country and region, and city when available) Else Then the audit records "Location not captured" with reason (jurisdiction restriction or user denial) Given the signer completes each required initial/signature/date field When each field is acted upon Then the audit records the field ID, action type, and timestamp And When the signer completes the signing Then the audit records the completion timestamp and signer confirmation
E-Records Consent and Disclosures
Given a signer opens a TapSign session When pre-sign disclosures are presented Then the disclosures include E-SIGN/UETA e-records consent text, hardware/software requirements, how to withdraw consent, and how to request paper copies Given the signer must provide explicit consent When the signer checks the consent box and continues Then the audit records consent granted with disclosure version identifier, timestamp, and contact channel And When the signer declines consent Then the session terminates without allowing signatures, the audit records consent declined with timestamp, and the matter reflects a "Consent Declined" status Given the signer completes signing When the session ends Then the signer can download or receive via email/SMS a copy of the signed document and the evidence summary
Tamper-Evident Evidence Summary and PDF Hash
Given signing is complete When the final PDF is generated Then the system computes a SHA-256 hash of the PDF bytes and stores it in the audit And the evidence summary page appended to the PDF displays the hash and key identity signals and timestamps Given the exported signed PDF and recorded hash When the hash is recomputed externally Then it matches the recorded hash And When the PDF is altered Then recomputation produces a different hash and verification fails Given a CaseSpark user views the audit When they invoke "Verify Document Integrity" Then the system validates the stored hash against the current file and returns a pass/fail result that is logged
Immutable Audit Log and Append-Only Events
Given audit events are persisted in CaseSpark When any user attempts to edit or delete an existing event via UI or API Then the action is denied with 403/operation not allowed, and the attempt itself is logged as a separate event Given a correction is required (e.g., updated signer contact) When the correction is made Then a new event is appended referencing the prior value and actor, preserving the original event unmodified Given an integrity check is run When the audit log’s event chain is verified Then the chain validates (e.g., sequential IDs and signed digests) And When any event has been altered Then verification fails and is surfaced in the UI and in exports
Audit Report Export and Matter Linkage
Given a matter with a completed TapSign session When a CaseSpark user views the matter Then the matter status updates to "Signed" and displays links to the signed PDF and the audit report Given the user exports the audit report When export is requested Then a PDF audit report is generated containing session ID, signer name, delivery channel phone number, OTP usage (required/optional/disabled), IP, user agent, geo data (if captured), timestamps, hash of final PDF, e-consent record, and full event timeline Given an audit report was previously exported When it is re-exported Then its contents (excluding generation timestamp) and computed checksums match the prior export And When the signing is incomplete Then export is unavailable and the UI indicates "Audit not available until signing completes"
Instant PDF Generation & Matter Sync
"As a solo attorney, I want the signed PDF and matter status to update automatically so that my next workflow steps kick off without manual work."
Description

On completion, flatten signatures and initials into a finalized PDF, append an audit summary page, and return the signed document instantly to the attorney and client via configured channels (download, email, secure link). Automatically attach the PDF to the CaseSpark matter, update matter status (e.g., "Retainer Signed"), and trigger downstream workflow automations (document assembly, filing, tasks). Provide webhooks and idempotent retries for integrations, with error handling, alerts, and reconciliation tools.

Acceptance Criteria
Finalized PDF Flattening
Given a TapSign session with all required signatures and initials completed When the signing session is finalized Then the generated PDF contains all signatures, initials, and date stamps visibly placed at the configured locations And the PDF has no editable form fields or interactive annotations (AcroForm/XFA removed) And the PDF renders without missing content in Acrobat, macOS Preview, and Chrome PDF viewer And an automated validation confirms there are zero interactive fields and zero unflattened annotations
Audit Summary Page Content & Placement
Given a completed signing and PDF generation When the final PDF is produced Then the last page is an appended audit summary after the signed content And the audit includes: unique document ID, SHA-256 document hash, signer names, masked phone numbers, delivery channels, IP addresses, event timestamps in UTC ISO 8601, device/OS/browser where available, and a chronological event log (sent, opened, signed) And the audit page clearly indicates the finalization timestamp and the responsible service version And automated checks verify the audit page exists and contains all required fields
Instant Return via Configured Channels
Given attorney and client notification channels are configured for the matter (download, email, secure link via SMS/WhatsApp) When the signing completes Then the signed PDF is available for immediate in-session download within 2 seconds And an email with the signed PDF attached (or a secure download link if >10 MB) is sent to configured recipients within 10 seconds And a secure SMS/WhatsApp link to the signed PDF is sent to the client within 10 seconds when enabled And disabled channels are not used And delivery outcomes (success/failure, timestamp) are recorded per channel for auditability
Matter Attachment & Status Sync
Given a matching CaseSpark matter exists for the TapSign session When the signed PDF is finalized Then the PDF is attached to the matter with a deterministic filename format {MatterID}_{DocType}_{YYYYMMDDHHmmss}.pdf And the matter status updates to "Retainer Signed" And a matter timeline entry is created with actor, timestamp, and link to the document And repeated callbacks or retries do not create duplicate attachments or multiple status changes (idempotent by document hash and session ID) And the attachment is immediately accessible via UI and API
Downstream Workflow Automations Trigger
Given automation rules exist for status "Retainer Signed" When the matter status is updated to "Retainer Signed" after attachment succeeds Then configured automations (document assembly, filing, task creation) are enqueued exactly once per finalized document And jobs receive the matter ID, document URL, and signer metadata as inputs And job execution order respects dependencies (assembly before filing, filing before dependent tasks) And failures in downstream jobs are logged and alerted without rolling back the attachment or status update
Outbound Webhooks Delivery & Idempotent Retries
Given at least one webhook subscription is configured When the document is finalized and matter sync completes Then a webhook POST is sent within 10 seconds containing event type, matter ID, document URL, document hash, and an idempotency key And the request is HMAC-SHA256 signed with the tenant's shared secret and includes signature headers And non-2xx responses trigger exponential backoff retries with jitter for up to 24 hours And repeated deliveries for the same idempotency key carry identical payloads, enabling receiver deduplication And an administrative replay action can resend specific events with the original idempotency key
Error Handling, Alerts, and Reconciliation Tools
Given any failure occurs during PDF generation, delivery, matter sync, automation, or webhook dispatch When the failure is detected Then the system records structured error logs with correlation IDs and captures metrics in monitoring And user-facing alerts are surfaced in the dashboard within 30 seconds and, when applicable, email notifications are sent to the attorney And safe automatic retries are attempted according to channel policies And a reconciliation view lists matters with missing attachments, mismatched statuses, or undelivered webhooks, with actions to retry, reattach, or resend And all manual remediation actions are audited with actor, timestamp, and outcome
Sign-to-Pay Handoff for Retainers
"As a practitioner, I want clients to pay the retainer right after signing so that I convert faster and minimize back-and-forth."
Description

Seamlessly route the signer to a PCI-compliant payment checkout immediately after the final signature, prefilled with retainer details from the matter. Support one-tap wallets (Apple Pay/Google Pay) where available, store payment confirmation alongside the signature audit, and update the matter’s financials and status on success. Handle declines with clear messaging, retry options, and staff notifications, and allow configuration of whether payment is required to consider the signing session complete.

Acceptance Criteria
Auto Handoff to PCI Checkout After Final Signature
Given a TapSign session with all required signatures collected When the final signature is applied and the envelope is marked signed Then the signer is automatically routed to a provider-hosted PCI-compliant checkout within 2 seconds, without additional login And the checkout URL is single-use and expires after 30 minutes or on successful payment, whichever comes first And the checkout metadata includes the matter ID, TapSign session ID, and retainer invoice/reference ID And no payment card fields are rendered within the TapSign domain
Prefilled Retainer Details in Checkout
Given the matter includes a retainer request with amount, currency, description, and client contact details When the checkout session is created Then the amount and currency are prefilled and locked to the retainer total from the matter And the description includes the matter reference and retainer label And the client's name, email, and phone are prefilled in billing fields when supported by the processor And all prefilled values exactly match the matter data
One‑Tap Wallet Support with Fallback
Given the signer’s device and browser support Apple Pay or Google Pay and the processor is configured for wallets When the checkout loads Then the appropriate wallet button is displayed above card entry And selecting the wallet completes payment without full card entry And if the device does not support wallets, the standard card form is displayed And strong customer authentication challenges are supported when required
Successful Payment Updates Audit, Matter, and Receipts
Given the payment is authorized and captured by the processor When the processor webhook confirms success Then a ledger entry is created on the matter for the exact amount and currency with transaction ID, payment method, and timestamp And the matter status changes to "Signed — Retainer Paid" within 5 seconds of webhook receipt And a payment receipt is stored and accessible to staff and sent to the client via SMS/email And the signature audit trail is appended with payment confirmation details and a hash linking the payment to the signed PDF
Declines, Retries, and Staff Notifications
Given the processor returns a decline or error When the checkout reports failure Then the signer sees a clear error message with plain-language guidance and a masked reason code And the signer can retry up to 3 times or choose an alternate method (different card or wallet) And no ledger entry is created and the matter status updates to "Signed — Payment Pending" And staff are notified within 60 seconds via configured channels with matter ID, client, and error code
Configurable Payment Requirement for Session Completion
Given the firm setting "Payment required after signing" is enabled When the signer completes all signatures but payment is not successful Then the signing session remains incomplete, signed PDFs are withheld from client delivery, and the TapSign link routes to the payment page on reopen And staff see an open task "Collect retainer" on the matter dashboard Given the firm setting is disabled When the signer completes all signatures but payment is not successful Then the signing session is marked complete, signed PDFs are delivered immediately, and a payment request task is created separately
Idempotent Processing and Double‑Charge Prevention
Given the signer refreshes the checkout, taps Pay multiple times, or a webhook is delivered more than once When backend payment events are processed Then only one successful ledger entry is created for a unique payment intent/transaction ID And duplicate events are acknowledged without additional charges or ledger entries And the signer receives a single confirmation and is not charged more than once
Link Lifecycle & Resend Controls
"As support staff, I want to manage and resend signing links safely so that clients can complete signing without creating duplicate matters or risking security."
Description

Provide administrative controls to set link expiration, maximum opens, and single-signer enforcement, with the ability to revoke, extend, or resend links via SMS/WhatsApp/email. Display real-time link status (sent, delivered, opened, completed, expired) in the matter timeline and enable client self-service "RESEND" via keyword reply. Invalidate links automatically when documents change, throttle resends to prevent abuse, and notify staff of expiring or stalled sessions.

Acceptance Criteria
Admin sets per-link expiration and open limits
Given an admin creates a TapSign link with expiration set to 72 hours and maximum opens set to 3 When the recipient opens the link the 1st, 2nd, and 3rd time before the expiration time Then access is granted each time and the open count is incremented and displayed in the matter timeline When the recipient attempts a 4th open before the expiration time Then access is denied with the reason "maximum opens reached" and the link status is recorded as expired due to open-limit in the matter timeline When the current time surpasses the configured expiration Then the link returns an "expired" message, cannot be used to sign, and the matter timeline records status=expired with a timestamp
Admin can revoke, extend, and resend via multiple channels
Given there is an active TapSign link for a signer When the admin selects Revoke from the matter console Then the link becomes unusable within 60 seconds, future opens show "link revoked", and the matter timeline records a revoked event with admin, signer, and timestamp When the admin selects Extend and adds 48 hours Then the link expiration updates immediately and the matter timeline records the previous and new expiration times When the admin selects Resend and chooses SMS, WhatsApp, or Email Then the signer receives the link via the selected channel(s) within 60 seconds, delivery events are captured where supported, and the matter timeline records a sent event per channel
Real-time link status and staff notifications in matter timeline
Given a matter with an active TapSign link When the system sends, delivers, is opened, completes, or expires the link Then the matter timeline shows a status entry (sent, delivered, opened with count, completed, expired) with signer, channel, and precise timestamp within 10 seconds of the event When a session is within 4 hours of its expiration and not completed Then assigned staff are notified via the configured channel (e.g., email/Slack/in-app) and the timeline records a notification-sent entry When a session is opened but not completed for 24 hours (stalled) Then assigned staff are notified and the timeline records a stalled-notification entry
Client self-service RESEND via SMS/WhatsApp
Given a signer has an active but incomplete TapSign session When the signer replies with the keyword RESEND (case-insensitive) in the original SMS/WhatsApp thread Then the system sends the current access link to the same channel within 60 seconds and records a client-self-resend event in the matter timeline When the session is already completed Then the system replies that the session is complete and does not resend a link When throttle limits are exceeded Then the system replies with a rate-limit message, does not resend, and records a throttle-blocked event
Automatic invalidation on document or signer changes
Given an active TapSign link exists for a signer When the underlying document package, field assignments, or signer list is changed and saved Then all outstanding links for affected signer(s) are invalidated within 60 seconds and any attempt to open shows "documents updated—request a new link" And the matter timeline records invalidated due to document change with details of the change And signing cannot proceed until a new link is sent by staff or via configured automation
Resend throttling and abuse prevention
Given resend throttling is configured to a minimum interval of 5 minutes and a maximum of 3 resends per 24 hours per signer per matter When admin-initiated or client keyword resends occur within limits Then the resend is processed and logged with a counter in the matter timeline When a resend is requested before 5 minutes have elapsed since the last send Then the system blocks the resend, returns a rate-limit message to the requester (if applicable), and logs throttle-blocked with next-allowed time When the 4th resend is requested within a 24-hour window Then the system blocks the resend, logs throttle-blocked, and (optionally) notifies assigned staff of possible abuse
Single-signer enforcement across devices and channels
Given a TapSign link is issued to Signer A via SMS/WhatsApp/email When the link is opened from the original channel/device/email by Signer A Then only Signer A’s fields are available and no other signer’s fields are accessible When the link is opened from a different device/channel/email than originally issued Then the system requires a one-time code sent to the original channel/email; if not verified, access is denied and the attempt is logged When a second device attempts access while an active session is in progress on another device Then the second device is blocked with a message indicating an active session exists When Signer A completes the session Then the link cannot be used again and is marked completed in the matter timeline
Smart Field Tagging & Autosnap Placement
"As a template admin, I want fields to auto-place and preview correctly on mobile so that clients sign in the right spots without staff rework."
Description

Map signature, initials, date, and form fields from CaseSpark templates into the signing session using anchor text tags and coordinate fallbacks. Autosnap and reflow fields across page shifts, font substitutions, or pagination changes to ensure precise placement on mobile. Provide a drag-and-drop field editor with versioning, conditional visibility, required/optional flags, and mobile preview to reduce setup errors and ensure consistent, accurate captures across jurisdictions and document variants.

Acceptance Criteria
Anchor Tag Mapping to Fields
Given a CaseSpark template containing anchor tags for fields (SIGNATURE, INITIALS, DATE, TEXT) with signer roles (e.g., [[SIGNATURE:Client]]) When a TapSign Link session is generated Then the system maps each anchor to a field of the correct type bound to the specified signer And field names and data keys are preserved from the template And indexed tags (e.g., [[INITIALS#2:Client]]) are ordered accordingly And escaped tags (e.g., \[[SIGNATURE:Client]]) are ignored And mapping completes in ≤2 seconds for a 10-page, 25-field PDF
Autosnap Placement Across Layout Changes
Given the output PDF differs from the template due to font substitution, scaling, or pagination When rendering the signing session on mobile and desktop Then each field snaps to its intended anchor region with ≤3mm positional error and baseline alignment within 2mm And no field overlaps body text or another field by >1pt And each field remains inside the page content box with ≥3mm padding And autosnap completes in ≤500ms per page
Coordinate Fallback and Anchor Conflicts
Given one or more anchors are missing, altered, or duplicated When generating the session Then the system places the field using last-published coordinates if available and logs a warning And if multiple matches exist, the system resolves using explicit index (#n) else nearest-text rule and flags duplicates for review And if neither anchor nor coordinates are available for a required field, the session cannot be sent and a validation error lists the missing fields with page references And optional fields with missing anchors are omitted without blocking
Drag-and-Drop Editor Versioning
Given a user edits fields in the drag-and-drop editor When they save changes Then a new version with incrementing semantic ID and change summary is created And the user can revert to any of the last 50 versions within 30 days And the audit log records user, timestamp, and changes And marking a version as Published makes it default for new sessions; existing sessions are unaffected
Conditional Visibility and Required Flags
Given fields have visibility rules using intake/matter data (e.g., county == "Travis" AND minor_children == true) When a session starts and data is loaded Then rules evaluate consistently server- and client-side And hidden fields are not rendered and are not validated And visible fields marked Required block completion until satisfied with inline error messages And rule evaluation adds ≤100ms latency for up to 50 rules
Mobile Preview Fidelity and Tap Targets
Given a user opens mobile preview in the editor for iOS and Android breakpoints When previewing portrait and landscape Then field positions and sizes match runtime within ±3mm and fonts within ±1pt And all interactive fields meet a ≥44x44 px touch target And no horizontal scroll is required to access any field And rotating the device preserves positions without drift

RulePulse

Continuously monitors state and county rules, standing orders, forms, and e‑filing provider notices. Delivers concise alerts with what changed, when it takes effect, which matter types are impacted, and recommended next steps. Auto‑tags affected templates and open matters so solos and small teams update once and avoid clerk rejections.

Requirements

Jurisdictional Rule Ingestion & Change Detection
"As a solo family-law attorney, I want the system to continuously detect and version rule and form changes across my jurisdictions so that I never miss an update and can prevent filing rejections."
Description

Continuously ingests and monitors official state and county court sources, standing orders, mandated forms repositories, and e‑filing provider bulletins. Normalizes all inputs to a unified schema (jurisdiction, court level, matter type, rule/form identifiers) and uses content fingerprinting plus semantic diffing to detect additions, removals, and amendments. De‑duplicates mirrored notices, captures provenance (source URL, fetch time, checksum), versions every change, and stores before/after snapshots. Supports scheduled polling with adaptive backoff, error handling, and robots.txt compliance. Includes an admin UI to manage sources and mappings to CaseSpark’s matter and template taxonomies, enabling downstream impact analysis.

Acceptance Criteria
Scheduler Polling with Adaptive Backoff and Robots Compliance
Given a source with a baseline poll interval of 1h, When 7 consecutive polls detect no changes, Then the next poll interval increases per backoff policy up to a maximum of 24h Given a change is detected on a source, When the scheduler computes the next run, Then the poll interval resets to the baseline for that source Given an HTTP 429 or 5xx response occurs, When retries are attempted, Then exponential backoff with jitter is applied up to 3 retries and the source is marked degraded without blocking other sources Given robots.txt disallows the target path, When the scheduler evaluates the fetch, Then the request is not made and a compliance warning is logged with the disallowed path Given a source has a polling window of 22:00–06:00 local time, When current time is outside that window, Then no fetch is performed and the next run is scheduled at the start of the next window
Normalization to Unified Schema and Provenance Capture
Given a fetched item from any supported source, When normalization completes, Then the record contains jurisdiction code, court level, matter type(s), rule/form identifiers, effective date, and version Given a normalized record, When stored, Then provenance includes source URL, fetch timestamp (UTC), SHA-256 checksum, and parser name/version Given jurisdiction is missing in the source, When mapping rules exist, Then jurisdiction is inferred and a confidence score ≥ 0.90 is stored; otherwise the record is flagged incomplete and excluded from downstream processing Given a record fails schema validation, When storage is attempted, Then the record is rejected and a validation error with field paths is logged
Content Fingerprinting and Semantic Diff Detection
Given identical content is fetched twice, When fingerprinting runs, Then the checksum matches and no new version is created Given content changes only in whitespace or formatting, When semantic diffing runs, Then the change is classified as non-substantive and no alert is emitted while a minor version increment is recorded Given textual changes that alter clauses or fields, When semantic diffing runs, Then the change is classified as amendment and both before/after snapshots are stored Given similarity falls below 0.85 to any known item, When comparison runs, Then the item is classified as an addition; if an existing item is removed from the source index, Then a removal change is recorded
De-duplication Across Mirrored Sources
Given two notices with identical checksums from different sources within a 24h window, When ingestion completes, Then a single change record is created with merged provenance listing both source URLs Given two notices have different checksums but share the same canonical URL, When de-dup logic runs, Then one unified record is kept and the duplicate is merged with a reason of canonical-match Given a duplicate is detected after initial storage, When merge occurs, Then no provenance fields are lost and an audit log entry records the merge time, source IDs, and winning record ID
Versioning and Before/After Snapshots
Given the first ingest of a rule/form item, When stored, Then version 1 is created with an immutable snapshot Given an amendment is detected, When versioning runs, Then the version increments by 1 and both new and prior snapshots are retrievable by version number Given a request to export the change history for an item, When fulfilled, Then the system returns a chronological list including version numbers, timestamps, change types (add/remove/amend), and semantic diffs
Admin UI for Source and Taxonomy Mapping
Given an admin user, When creating a source, Then required fields (name, base URL, parser type, polling interval/window, credentials) are validated and saved Given a configured source, When the user clicks Test Fetch, Then the most recent item is fetched in sandbox and a normalization preview is displayed within 5 seconds at the 95th percentile Given mapping rules from source attributes to CaseSpark matter/template taxonomy, When test cases are executed, Then expected target tags are produced with pass/fail indicators Given a user without Admin role, When accessing the Sources screen, Then create/update/delete actions are not available and are hidden or disabled
Error Handling, Alerts, and Observability
Given a fetch fails for a source, When the attempt completes, Then an alert is created including source ID, error code, first failure time, retry count, and next retry time Given failures persist for more than 12 hours, When alerting policy evaluates, Then severity escalates and a notification is sent to the configured channel Given normal operation, When metrics are emitted, Then dashboards show per-source fetch latency, success rate, change detection rate, dedup rate, and current backoff level for the last 24 hours
Effective Date & Impact Extraction
"As a practice administrator at a two-attorney firm, I want RulePulse to pinpoint when a change takes effect and which of our active matters are impacted so that we can prioritize updates and avoid last-minute surprises."
Description

Automatically parses effective dates, applicability windows, and impacted matter types from notices and orders using a hybrid of rules, regex, and NLP. Extracts key attributes (e.g., takes effect date, sunset date, filing preconditions, new form numbers) and maps them to CaseSpark’s jurisdiction and matter taxonomy with confidence scoring. Provides a review queue for low-confidence items, highlights changed sections, and links each extracted field to its source text span. Supports manual overrides, versioning of extractions, and propagation of corrections to downstream alerts and tags.

Acceptance Criteria
Concise Multi-Channel Alerts & Digests
"As a solo attorney on the go, I want clear, concise alerts with the effective date and impact delivered to my preferred channel so that I can act quickly without sifting through full court orders."
Description

Generates concise alert cards that summarize what changed, when it takes effect, which matter types are impacted, and provides a link to recommended next steps and the source. Delivers notifications via in‑app, email, and SMS with user-level preferences for jurisdictions, matter types, urgency, and delivery cadence (immediate, daily, weekly). Deduplicates related events, rate-limits bursts, supports snooze and acknowledgment, and produces digest views grouped by jurisdiction and effective date. Deep-links to the full diff, evidence, and one-click remediation actions within CaseSpark.

Acceptance Criteria
Auto-Tag Templates & Open Matters
"As a paralegal, I want affected templates and active cases to be auto-tagged and queued for updates so that we can update once and maintain consistency across all filings."
Description

Automatically identifies and tags affected templates, clause libraries, checklists, and open matters based on jurisdiction, matter type, stage, and required documents. Creates impact tags and update tasks, and surfaces a batch-update workflow to apply template revisions to all impacted matters with safeguards (diff preview, rollback, per-matter opt-out). Synchronizes tags with CaseSpark’s document assembly and intake workflows to ensure new filings reflect updated requirements and forms.

Acceptance Criteria
Recommended Next Steps Generator
"As a small-firm owner, I want RulePulse to suggest concrete tasks when rules change so that our team spends less time interpreting notices and more time implementing fixes."
Description

Transforms detected rule changes into actionable, jurisdiction-aware guidance and tasks (e.g., update clause X, swap to new form Y, adjust deadline Z). Provides one-click creation of pre-filled tasks with due dates computed from effective windows and assigns them to the appropriate role. Allows admins to customize and publish firm-specific playbooks that augment the autogenerated guidance, ensuring consistent execution across the team.

Acceptance Criteria
Source Transparency & Audit Trail
"As a compliance-conscious attorney, I want a complete audit trail of rule changes and our responses so that I can defend our process and train new staff."
Description

Maintains a verifiable audit trail for every change event, including source URLs, fetch timestamps, raw content snapshots, diffs, parser outputs with confidence scores, reviewer actions, alerts delivered, tags applied, and tasks created. Supports search, filtering, export (PDF/CSV), and retention policies. Enforces role-based access controls and provides an evidence package to justify updates if questioned by clerks or during internal QA.

Acceptance Criteria
Resilience, Monitoring & Backfill
"As a firm owner, I want reliable and timely alerts even during outages so that critical rule changes are not missed."
Description

Defines SLOs for source polling frequency and alert delivery latency. Implements health checks, retries, circuit breakers, and dead-letter queues for failed fetches/parses. Detects coverage gaps and automatically backfills missed periods after outages. Provides observability dashboards, anomaly detection on source volumes, alert suppression for known issues, and on-call notifications. Ensures secure storage, least-privilege access, and compliance with data handling policies.

Acceptance Criteria

FeeMatrix

Maintains live filing fee schedules by county and filing channel. Auto‑calculates totals, mandatory add‑ons, service fees, and waiver eligibility, updating client quotes inside packets. Warns when fees change between intake and filing and adjusts payment requests automatically to prevent underpayment delays.

Requirements

County Fee Schedule Ingestion & Versioning
"As a practice owner, I want FeeMatrix to keep county fee schedules accurate and versioned so that quotes and payments always reflect the current rules without manual re-entry."
Description

Implement a data pipeline and admin console to maintain live filing fee schedules by county, court, and filing channel with effective-date versioning. Support multiple ingestion modes (web-scraped monitors, manual admin edits, CSV/Excel import, and partner APIs) with validation rules, required fields (fee code, description, conditions, amount, unit, effective dates), and audit history of changes. Enable granular scoping (e.g., per case type, motion, service method, page count thresholds) and mandatory add-ons (e.g., e-filing service fees, surcharges) captured as rules. Provide automated change detection, conflict resolution workflows, and rollbacks. Expose read-optimized cache for low-latency lookups by downstream FeeMatrix components and log provenance for compliance.

Acceptance Criteria
Jurisdiction-Aware Fee Mapping
"As an intake specialist, I want the system to auto-select the correct county and channel fee schedule so that I don’t waste time guessing which fees apply."
Description

Create a resolver that maps matter metadata (jurisdiction, county, court, filing channel, case type, motion/subtype, service method) from CaseSpark intake to the correct fee schedule and rule set. Handle edge cases such as missing county-channel combinations, temporary court directives, and exceptions with admin overrides. Provide deterministic selection with traceable reasoning, including fallback precedence and warnings when data is incomplete. Cache resolved mappings per matter to ensure consistent calculations across the intake-to-filing lifecycle and respect effective dates based on intended filing date.

Acceptance Criteria
Comprehensive Fee Calculation Engine
"As a solo attorney, I want an itemized, accurate fee breakdown auto-calculated from my matter details so that I can quote clients confidently and avoid underpayment rejections."
Description

Deliver a rule-driven calculation engine that computes totals, itemized lines, mandatory add-ons, service fees, and taxes based on the selected fee schedule and matter parameters (party count, pages, copies, service method, urgency). Support conditional tiers, per-unit fees, caps, exemptions, and court-specific rounding. Return a structured breakdown (line items, subtotals, surcharges, waivers applied, payable now vs at acceptance) with currency formatting and localized display. Provide a deterministic contract for downstream consumers (intake UI, packet generator, payments) and expose what-if recalculation for scenario planning without mutating the matter state.

Acceptance Criteria
Automated Waiver Eligibility Evaluation
"As a client-facing attorney, I want the system to determine fee waiver eligibility during intake so that I can present accurate quotes and required steps without rework later."
Description

Implement waiver logic that evaluates eligibility based on configurable guidelines (income, household size, assets, case category, county policy) with support for federal poverty level updates and county overrides. Collect required intake data with validation, compute eligibility and partial reductions, and surface rationale and documentation checklist. Output a structured waiver recommendation to the calculation engine to adjust totals and to document assembly to pre-fill relevant forms and client communications. Clearly flag assumptions and missing data, and maintain an auditable record of inputs and outcomes for compliance.

Acceptance Criteria
Real-time Quote Updates in Intake & Packets
"As a prospective client, I want my quoted filing costs to update instantly as my details change so that I understand what I’ll pay before I sign."
Description

Integrate FeeMatrix outputs into CaseSpark’s intake flows and document/packet generation so that quotes update instantly when users change county, channel, filing date, service method, or other parameters. Provide responsive UI components that display itemized fees, waiver impacts, and payable-now totals, and inject the same breakdown into emails, proposals, and e-sign packets via template tokens. Ensure recalculations are non-blocking, gracefully handle stale data with refresh prompts, and record the quote version used for client-facing documents.

Acceptance Criteria
Fee Change Detection & Payment Adjustment
"As a filing attorney, I want automatic alerts and payment adjustments if fees change before filing so that my submission isn’t rejected for underpayment."
Description

Monitor effective-date changes between initial quote and filing time. When a schedule updates, recalculate the matter, highlight deltas, and automatically adjust payment requests to prevent underpayment delays. Support configurable flows: auto-collect difference with saved authorization, request additional payment via secure link, or require attorney approval. Send notifications to staff and clients, update packet totals, and preserve an audit trail of the original quote, change reason, and final amount charged. Ensure idempotent updates and safe retries with the payment gateway.

Acceptance Criteria

ClauseCompass

At assembly, proposes the correct county‑specific clause variants and paragraph revisions with plain‑language rationale and rule citations. One tap applies the language across all relevant documents and saves preferences, cutting research time and last‑minute edits.

Requirements

Jurisdiction & County Resolver
"As a family-law attorney, I want CaseSpark to automatically resolve the correct county for a matter so that clause recommendations match the local rules without manual lookup."
Description

Automatically determine and persist the correct county jurisdiction for each matter by combining intake answers (addresses, court selection, venue factors) with geocoding and court-mapping logic. The resolver exposes a single source of truth used by ClauseCompass and the document assembly pipeline, with support for multi-county edge cases, venue overrides, and confidence indicators. It logs provenance (how the county was derived), gracefully prompts for missing data, and updates downstream recommendations when jurisdiction changes.

Acceptance Criteria
Clause Variant Recommendation Engine
"As a drafting attorney, I want the system to recommend the correct clause variants during assembly so that I can assemble filings faster and with fewer errors."
Description

Generate county-specific clause and paragraph recommendations at assembly time based on jurisdiction, document type, case posture, and party attributes. The engine applies deterministic business rules anchored in local rules and standing orders, evaluates applicability conditions and dependencies, scores options, and surfaces the top variant(s) with a concise diff vs. the current template text. It integrates with the assembly pipeline, supports per-document contexts, and validates that selected variants meet required conditions before insertion.

Acceptance Criteria
Plain-Language Rationale & Rule Citations
"As a practitioner, I want plain-language explanations with rule citations for each suggested clause so that I can trust and verify the recommendations quickly."
Description

Display an explainable rationale for each recommendation in plain language alongside authoritative citations (local rules, standing orders, court websites) with effective dates, links, and excerpted passages. The UI supports quick expand/collapse, copy-to-clipboard, and accessibility standards. Rationale artifacts are captured in an audit trail, tied to the chosen variant and jurisdiction, and are available in matter history for later review or challenge.

Acceptance Criteria
One-Tap Global Apply
"As a busy attorney, I want to apply a selected clause variant across all relevant documents with one tap so that I avoid repetitive edits and maintain consistency."
Description

Apply a selected clause variant across all relevant documents in the current assembly bundle with a single action, maintaining formatting, numbering, and references. The system previews impact (files and locations affected), supports selective apply, and provides undo/redo. It detects conflicts with manual edits, offers resolution options, and records changes in the document change log for traceability.

Acceptance Criteria
Preference Learning & Auto-Defaults
"As a solo attorney, I want the system to remember my preferred clause choices by jurisdiction so that future assemblies start with my defaults and require fewer changes."
Description

Learn and store per-user and firm-level clause preferences keyed by jurisdiction, document type, and context, then pre-select preferred variants when confidence is high while allowing easy override. Provide an admin UI to manage presets, scope (user/team/firm), and exceptions, with export/import and audit logs. Preferences never suppress mandatory rule-driven selections and are clearly indicated in the UI when applied.

Acceptance Criteria
Template Anchor Mapping & Safe Replace
"As a template maintainer, I want clause replacements to target the correct sections without breaking numbering or custom edits so that documents remain clean and compliant."
Description

Introduce semantic anchors in templates to locate clause regions and safely replace or insert text without breaking structure. When anchors are absent, use robust pattern matching and structural heuristics to identify targets. Ensure numbering, cross-references, table of contents, and defined terms update correctly. Protect user customizations by scoping replacements, supporting granular review, and providing idempotent operations to prevent duplicate insertions.

Acceptance Criteria
Rule Content Management & Versioning
"As a managing attorney, I want a versioned rules and clause library with effective dates so that our filings always reflect current local requirements and we can audit past work."
Description

Provide a back-office CMS for county-specific clause texts, applicability conditions, and citations with full versioning, effective date windows, approvals, and rollback. Editors can schedule updates, compare diffs, and map changes to impacted templates and documents. The system enforces integrity checks, flags conflicts, notifies users of rule changes during assembly, and preserves historical versions for audit and reproduction of past filings.

Acceptance Criteria

RevisionGuard

Flags outdated forms and templates with effective‑date awareness. Provides a safe upgrade wizard with side‑by‑side diffs, a test‑fill sandbox, version pinning per matter, and one‑click rollback—so you can adopt changes confidently without breaking active filings.

Requirements

Effective-Date Template Registry & Jurisdiction Sync
"As a managing attorney, I want templates to carry authoritative effective dates and jurisdiction metadata so that my team can rely on compliant, traceable forms during assembly."
Description

Centralized registry that stores every template’s version, effective date, source authority, jurisdiction, and change notes, synced from court and bar repositories on a scheduled cadence and via on-demand refresh. The registry exposes a read API to CaseSpark’s document assembly engine and intake workflows, ensuring forms pulled into matters always reference authoritative metadata. Includes de-duplication across jurisdictions, mapping to CaseSpark practice areas, and validation rules that reject templates lacking effective-date metadata. Guarantees traceability by linking each template version to its provenance and changelog, enabling downstream flagging, upgrades, and compliance evidence.

Acceptance Criteria
Global Outdated Form Detector
"As a paralegal, I want the system to flag any outdated forms in my active matters so that I don’t miss required updates before filing."
Description

Background service that continuously compares templates and matter-attached forms against the registry to detect superseded versions. Surfaces non-blocking alerts in the template library and at the matter level with severity based on proximity to the effective date and filing deadlines. Provides quick filters (by jurisdiction, practice area, deadline risk) and bulk-select actions to launch the upgrade wizard. Integrates with CaseSpark notifications (in-app, email) and respects user roles to avoid alert fatigue while ensuring no active filing proceeds with stale forms unnoticed.

Acceptance Criteria
Safe Upgrade Wizard (Diff + Field Mapping)
"As an attorney, I want a guided way to upgrade forms that preserves my entered data so that I can adopt updates without rework or errors."
Description

Interactive flow that compares current and new template versions side-by-side, highlighting textual changes, clause movements, and field schema diffs (added/removed/renamed/validation changes). Suggests intelligent field mappings to preserve data already collected in CaseSpark intake, with confidence indicators and manual override. Provides pre-upgrade checks (dependencies, jurisdiction rules) and generates a preview of the assembled document in the new version. On confirmation, upgrades the template in-place or clones it per matter, preserving a link to the prior version for rollback.

Acceptance Criteria
Test-Fill Sandbox Runner
"As a paralegal, I want to trial an updated form with my matter’s data in a safe sandbox so that I can verify nothing breaks before I commit the change."
Description

Isolated environment to test-fill upgraded templates using real matter data snapshots without touching the live record. Supports seeded edge cases (empty required fields, long strings, date formats) and jurisdiction validations to reveal breakages before committing the upgrade. Captures a validation report and renders a downloadable preview PDF/DOCX. Integrates with the upgrade wizard for one-click sandbox runs and stores test artifacts for audit and team review.

Acceptance Criteria
Version Pinning per Matter
"As a solo attorney, I want to pin a matter to a known-good form version so that my filings stay consistent until the case stage safely allows an upgrade."
Description

Ability to lock a matter to a specific template version, with visible badges on the matter timeline and assembly screens. Includes policy controls (admin-defined) for auto-pinning at creation, reminders when newer versions exist, and override prompts requiring justification if filing after a supersede date. Ensures consistent outputs across a matter’s lifecycle and prevents inadvertent partial upgrades across related documents.

Acceptance Criteria
One-Click Rollback with Audit Trail
"As a managing attorney, I want the option to instantly rollback a template upgrade with a clear audit trail so that I can mitigate risk if an update introduces issues."
Description

Immediate reversion from an upgraded template back to the prior version, restoring field mappings and data compatibility. Generates an immutable audit entry recording who initiated the rollback, why, timestamps, affected matters, and artifacts (diff, sandbox report). Exposes an exportable compliance packet to attach to the matter record, demonstrating due diligence in template management for court inquiries or malpractice defense.

Acceptance Criteria
Impact Analysis & Notifications
"As an operations lead, I want to see which matters a form change will impact and notify the right people so that we prioritize upgrades without jeopardizing deadlines."
Description

Dashboard and service that forecast which active matters, deadlines, and downstream documents are affected by a template change before and after upgrade. Computes risk scores based on filing dates, jurisdictional strictness, and dependency chains (e.g., attachments, referenced forms). Sends targeted notifications to responsible users and routes approvals to designated reviewers for high-risk changes. Integrates with CaseSpark’s calendar and tasking to auto-create follow-ups for upgrades due within configurable windows.

Acceptance Criteria

CountyQuirks

Surfaces local idiosyncrasies—wet signatures, notarization, page limits, staple rules, required cover sheets, and hearing lead times. Runs a preflight check before send/e‑file and auto‑inserts needed captions or forms, reducing rejections and courthouse trips.

Requirements

County Rules Knowledge Base & Versioning
"As a legal ops admin at a small firm, I want a centralized, versioned repository of county filing rules so that our filings always reflect the latest local requirements and we can audit changes."
Description

Create an authoritative, structured repository of county- and court-specific filing requirements (e.g., wet signature mandates, notarization types, page limits, staple/fastener rules, required cover sheets, document codes, PDF standards, fee schedules, and hearing/notice lead times). Each rule includes effective dates, sources/citations, evidence attachments (e.g., rule PDFs), and change history with versioning and rollback. Provide an admin curation UI with role-based permissions, validation rules, and draft/publish workflow. Expose a query API for downstream components with caching and graceful degradation. Include automated ingestion and monitoring to detect updates (e.g., court notices), plus unit tests and data integrity checks to ensure accuracy and auditability.

Acceptance Criteria
Jurisdiction Detection & Routing
"As an intake paralegal, I want CaseSpark to determine the correct county and court from matter details so that the right local rules are applied without manual research."
Description

Determine the correct county and court division for each matter using intake data (party addresses, property/school districts, case type), geocoding, and venue heuristics. Present confidence scoring and allow manual confirmation/override. Map the identified jurisdiction to the applicable rule set in the knowledge base, including edge cases (multi-county implications, concurrent jurisdiction). Log decisions for audit, and surface the chosen jurisdiction context to all downstream workflows (document assembly, preflight, packaging). Provide API/SDK hooks so third-party intake sources can supply or consume jurisdiction decisions.

Acceptance Criteria
Preflight Compliance Check Engine
"As an attorney, I want an automated preflight check before e-filing so that I can fix issues proactively and avoid clerk rejections."
Description

Implement a rules-driven preflight engine that evaluates the assembled filing packet against county-specific requirements prior to send/e-file. Validate page limits, margin and font settings, exhibit labeling, caption format, mandatory forms and cover sheets, required document codes and ordering, signature modality, notarization presence, and physical-only constraints (e.g., staple/binder rules if physical filing is selected). Generate an actionable checklist with blocking errors vs warnings, recommended auto-fixes, and one-click remediation where possible. Provide JSON and UI outputs, batch processing, and integration with the existing send/e-file flow. Record results for analytics and re-check after any edits.

Acceptance Criteria
Auto-Insert Local Forms & Captions
"As a solo attorney, I want required county cover sheets and caption formats inserted automatically so that I don’t waste time hunting and formatting local forms."
Description

Automatically insert county-required cover sheets, caption formats, and local forms into the compiled packet based on jurisdiction and case type. Merge matter data into form fields, enforce page order and section placement, and ensure PDF conformance (e.g., PDF/A, bookmarks). Maintain a versioned template library per county/division with preview, inline editing, and firm-level customization. Track which artifacts were applied and why, and re-apply on re-generation. Provide per-matter overrides with audit logging, and validate that insertions satisfy preflight checks.

Acceptance Criteria
Signature & Notarization Orchestration
"As a practitioner, I want the system to handle signature and notarization requirements per county so that filings meet acceptance criteria without me coordinating logistics."
Description

Determine signature modality from county rules (wet vs e-sign) and orchestrate the required steps. If e-sign is permitted, route documents through CaseSpark’s e-sign flow with appropriate signer roles and seals; if wet signatures or notarization are required, generate a print packet, provide step-by-step instructions, optionally schedule a mobile notary via partner integrations, and capture scanned notarized pages with OCR validation. Attach notarial certificates and maintain a chain-of-custody and audit trail. Provide reminders and status tracking so filings are not delayed by signature logistics.

Acceptance Criteria
E-Filing Portal Packaging & Submission
"As an attorney, I want CountyQuirks to package and submit my filings correctly to each county’s portal so that they are accepted on the first attempt."
Description

Package documents and metadata according to each county portal’s specifications (e.g., Tyler eFile/Odyssey and local portals): assign lead/attachment roles, document type codes, naming conventions, and envelope structure; ensure PDF standards, file size limits, and encryption settings are met. Populate required metadata (case category, party roles, fees), calculate and present expected fees, manage payment tokens, and submit via secure APIs. Track submission IDs, poll for status, parse acceptance/rejection reason codes, and surface actionable remediation steps with one-click resubmission. Provide sandbox modes and rate-limit handling.

Acceptance Criteria
Lead Time & Calendar Advisories
"As a family-law attorney, I want guidance on local hearing lead times and notice requirements so that I can pick dates that comply and avoid continuances."
Description

Compute county-specific hearing lead times, notice requirements, and filing deadlines from the knowledge base and court calendars. When the user proposes dates, validate compliance and suggest the earliest permissible windows. Auto-create calendar holds, reminders, and service timelines; account for weekends, holidays, and court blackout dates. Warn when compliance is not feasible and propose alternatives (e.g., different hearing type or expedited motions where allowed). Keep advisories current when rules or calendars change and annotate matters with the assumptions used.

Acceptance Criteria

VenueSense

Analyzes parties’ addresses, school zones, and event locations to recommend the proper venue and close alternatives. Prefills county fields, updates the required forms list, and flags cross‑county requirements (e.g., parenting classes), preventing misfilings and restarts.

Requirements

Geospatial Data Ingestion & Normalization
"As a solo family-law attorney, I want addresses and locations to be accurately parsed and mapped to the correct counties and boundaries so that venue recommendations are reliable and I avoid misfilings."
Description

Implement a data pipeline that validates and geocodes all party and event addresses, resolves them to canonical county and court-boundary identifiers, and enriches with school-zone polygons where applicable. Support multiple input sources (phone intake, web forms), normalize address formats, and cache results to minimize latency and API costs. Maintain fallbacks to offline datasets for high availability, record data provenance and versioning, and expose a consistent internal API to VenueSense and downstream modules (conflict screening, document assembly). This ensures accurate, explainable venue inputs and seamless integration across CaseSpark.

Acceptance Criteria
Rule-Based Venue Determination Engine
"As a practitioner, I want a clear, rules-driven venue recommendation with alternatives so that I can file in the correct county and explain the choice to clients or the court."
Description

Provide a configurable, jurisdiction-aware rules engine that determines the proper venue based on case type (e.g., divorce, custody), parties’ domiciles, children’s residency timelines, and relevant event locations. The engine outputs a ranked recommendation with confidence, rationale, and close alternatives, handling edge cases (multiple children, recent moves, protective orders) and tie-breakers. Rules are versioned and editable via admin UI without code deployment, with audit logs and test fixtures to validate changes. The engine exposes APIs to prefill UI fields, update required forms, and inform task creation.

Acceptance Criteria
County & Court Prefill Sync
"As an intake specialist, I want county and court fields to auto-populate from the recommendation so that I can move from call to filing faster with fewer manual errors."
Description

Automatically prefill county and court fields across intake workflows, matter records, and document assembly based on the top venue recommendation. Support two-way sync: user adjustments update the matter and document merge fields; finalized venue locks critical fields while allowing an explicit override flow. Provide real-time validation and visual indicators when the venue changes, and ensure audit trails capture who changed what and when for compliance and traceability.

Acceptance Criteria
Dynamic Forms & Cross-County Requirements Resolver
"As an attorney, I want the forms and requirements to update automatically with the chosen venue so that I don’t miss venue-specific steps that cause delays or restarts."
Description

Dynamically generate the required forms list and ancillary requirements (e.g., county-specific parenting classes, mediation prerequisites, affidavits) based on the selected or recommended venue and case type. Update e-filing eligibility, fees, and signature needs in real time. Provide links to approved providers by county, create tasks with due dates, and flag mismatches (e.g., parties in different counties triggering special notices). Expose this list to document assembly so that only venue-appropriate templates are offered.

Acceptance Criteria
Venue Override & Justification Capture
"As a lead attorney, I want to override the recommended venue with a recorded rationale so that I can exercise judgment on edge cases while keeping the team compliant and auditable."
Description

Enable authorized users to override the recommended venue with mandatory justification, including reason selection, free-text explanation, and optional citation to firm-configured guidance. Upon override, recompute forms, fees, and requirements and record a full audit entry. Surface the rationale in the matter timeline and make it available for inclusion in filings or internal review. Log overrides as feedback data to improve rules and monitor accuracy over time.

Acceptance Criteria
Data Currency & Boundary Updates
"As a managing partner, I want confidence that venue boundaries and requirements are up to date so that our filings reflect current rules and we avoid costly errors."
Description

Establish a scheduled update pipeline for county/court boundaries, school-zone maps, and venue-related reference data with source whitelisting, checksums, and automated regression tests against canonical addresses. Provide versioning, change diffs, alerting when data becomes stale, and one-click rollback. Display dataset versions within matters for transparency, ensuring VenueSense decisions are made on current, trustworthy data.

Acceptance Criteria

Schema Scout

Automatically detects spreadsheet and Clio field patterns, then proposes best‑fit mappings to CaseSpark’s family‑law schema. Flags ambiguities (e.g., “Spouse” vs. “Opposing Party”) with plain‑language suggestions and sample previews so you confirm once and save a reusable preset—cutting setup time and mapping errors.

Requirements

Auto Field Pattern Detection & Ranked Suggestions
"As a firm administrator, I want Schema Scout to auto-detect and suggest mappings from my spreadsheets and Clio so that I can configure imports quickly without manual field-by-field setup."
Description

Analyze spreadsheet headers, sample values, and Clio field metadata to automatically detect likely mappings to CaseSpark’s family‑law schema. Use heuristics and ML-backed similarity (string, semantic, data type, value distribution) to propose top suggestions per source field with confidence scores and rationale hints. Support CSV/XLSX uploads and pre-ingested Clio field catalogs. Handle common synonyms (e.g., Spouse, Opposing Party, Respondent) and multi-entity structures (parties, children, addresses). Output a draft mapping set that can be reviewed and edited before application, reducing setup time and mapping errors while fitting seamlessly into CaseSpark’s intake/import workflow.

Acceptance Criteria
Ambiguity Flagging & Clarification UX
"As a paralegal, I want ambiguous mappings to be clearly flagged with simple explanations and previews so that I can confidently resolve them without breaking downstream documents."
Description

Detect ambiguous or colliding fields (e.g., Spouse vs. Opposing Party; Child Name vs. Minor) and surface plain-language prompts explaining why the mapping is uncertain. Provide side-by-side sample value previews, recommended choices, and tooltips describing the implications for downstream document assembly. Enable quick disambiguation actions (pick one, split column, map to relation) and inline corrections. Persist resolved decisions into the draft mapping and feed outcomes back to improve future suggestions.

Acceptance Criteria
Clio Field Sync & OAuth Integration
"As a solo attorney using Clio, I want Schema Scout to pull my Clio custom fields securely so that the mapping suggestions reflect my firm’s actual data model."
Description

Establish secure OAuth-based connection to Clio to fetch standard and custom field definitions, labels, and picklist values relevant to family-law matters. Cache and periodically refresh metadata with respect to rate limits and scopes. Normalize Clio field structures into a unified catalog consumable by Schema Scout’s suggestion engine. Provide account-level controls to connect/disconnect, re-authenticate, and scope consent. Ensure transport security, token storage hygiene, and error handling that gracefully falls back to local mapping without Clio.

Acceptance Criteria
Reusable Mapping Presets & Versioning
"As an operations manager, I want to save and reuse mapping presets so that future imports require only a one-click apply instead of reconfiguration."
Description

Allow users to save confirmed mappings as named presets keyed by source signature (e.g., column set hash, Clio account) and jurisdiction context. Support versioning with change history, comparison, rollback, and notes. Enable preset sharing within the firm with role-based permissions (view/use/edit). Provide quick-apply during future imports and show preset fit score when sources partially match. Manage preset lifecycle (create, clone, deprecate) and ensure compatibility checks against evolving CaseSpark schema.

Acceptance Criteria
Sample Preview & Validation Checks
"As a legal assistant, I want to preview how my data maps and see validation issues before I commit so that filings won’t fail later in the workflow."
Description

Render an interactive preview showing several source rows mapped into CaseSpark’s target schema, including nested party/child structures. Validate required fields, data types, formats, and jurisdiction-specific requirements; highlight errors and warnings inline. Offer quick fixes (e.g., split full name, normalize phone, select jurisdiction) and re-run validation in real time. Block finalization on critical errors while allowing export of a validation report. Ensure previews perform on large datasets by sampling with user-adjustable size.

Acceptance Criteria
One-Click Apply, Rollback & Audit Trail
"As a practice owner, I want to apply mappings confidently and revert if needed so that my data integrity and compliance are preserved."
Description

Provide a single action to apply the approved mapping to the import pipeline, with a dry-run summary of created/updated records. Support instant rollback to the previous state and capture a complete audit trail (who, when, what changed, before/after) for compliance. Expose logs for export and include correlation IDs for support. Integrate with CaseSpark notifications to confirm success/failures and suggest next steps (e.g., document assembly). Ensure idempotent operations to prevent duplicate records on retries.

Acceptance Criteria

CleanLift

Cleans and normalizes imported data on the way in—fixing name casing, unifying date/phone formats, validating emails, and standardizing addresses. Presents a pre‑import quality score and one‑click fixes with undo, so you start with court‑ready data instead of post‑migration cleanup.

Requirements

Pre-Import Quality Scoring
"As a solo attorney, I want a clear pre-import quality score so that I can confidently import only court-ready data and avoid cleanup after matters are created."
Description

Profiles incoming CSV/API datasets to detect casing issues, malformed or ambiguous dates, non-E.164 phone numbers, invalid emails, incomplete addresses, and likely duplicates before data is committed. Computes a per-record and batch quality score with categorized findings and recommended fixes. Surfaces a preview panel with inline diffs and estimated impact of applying fixes. Supports gating imports by minimum score, exporting an issue report, and tagging cleaned records for downstream intake, conflict screening, and document assembly. Operates within CaseSpark’s import pipeline with streaming analysis for large files and preserves raw values for traceability.

Acceptance Criteria
Smart Name Casing
"As an intake specialist, I want names automatically cased to legal standards so that documents look professional and consistent without manual edits."
Description

Normalizes party and contact names to legal-ready casing while preserving intentional stylization and suffixes (e.g., Jr., III), handling hyphenated surnames, prefixes (O’, Mc), multi-part surnames, and entity names. Applies configurable exception dictionaries and style guides per court. Distinguishes individual vs. organization names, respects DBA/AKA notations, and keeps the original input in an immutable field for audit and reversion. Integrates with conflict screening and document assembly to ensure consistent appearance across filings.

Acceptance Criteria
Locale-Aware Date & Phone Normalization
"As a paralegal, I want dates and phone numbers automatically normalized so that filings and notifications use correct, consistent formats across jurisdictions."
Description

Parses and standardizes dates and phone numbers from varied formats into court-compliant display formats and canonical storage. Dates are normalized with unambiguous ISO storage, timezone awareness, and validation against reasonable ranges (e.g., DOB not in the future). Phone numbers are validated and stored in E.164 with extension support, while displaying in jurisdiction-appropriate format. Flags partial or ambiguous inputs for review and provides suggested fixes. Ensures consistent data for conflict checks, reminders, and document merge fields.

Acceptance Criteria
Email Verification & Merge
"As a firm owner, I want unreliable or duplicate emails flagged and resolved during import so that client communications don’t bounce and my CRM stays clean."
Description

Validates email addresses with syntax checks, domain/MX verification, and optional deliverability checks to flag high-risk or disposable addresses. Canonicalizes case and common provider-specific variants and uses emails as a deduplication signal to prevent creating redundant contacts during import. Presents suggested merges with side-by-side field diffs and preserves a full audit trail of chosen resolutions. Minimizes external data exposure by using privacy-safe checks and configurable network policies.

Acceptance Criteria
Court-Standard Address Normalization
"As a legal assistant, I want addresses standardized and validated so that court forms prefill correctly and mailings reliably reach clients and parties."
Description

Standardizes addresses using postal standards (e.g., USPS CASS/DPV for US, Canada Post SERP where applicable, and libpostal for international), correcting street abbreviations, unit designators, and city/state formatting. Validates deliverability, identifies PO Boxes, and maps components to CaseSpark’s structured address model. Provides jurisdictional hints (county, state) for routing and document assembly and enforces line-length and character constraints common on court forms. Retains original input alongside the standardized address for reference and rollback.

Acceptance Criteria
One-Click Fix & Undo
"As an intake coordinator, I want to apply all safe fixes in one click with the ability to undo so that I can import quickly without risking irreversible changes."
Description

Offers a single action to apply all recommended fixes or selected categories (names, dates/phones, emails, addresses) with transactional safety. Shows per-field diffs, impacted records, and an estimated quality score lift before committing. Provides instant undo, multi-level rollback, and a persistent change log linked to the import batch and user. Ensures idempotent application to avoid double-cleaning and integrates with error handling to isolate and skip problematic records without blocking the batch.

Acceptance Criteria
Rule Profiles by Jurisdiction
"As a managing attorney, I want cleansing rules tailored by court and matter type so that imported data matches local filing standards without manual tweaks."
Description

Enables administrators to configure and assign cleansing rule profiles per jurisdiction, court, and matter type (e.g., CA family law date format, address abbreviations, name styling). Supports versioned profiles, safe testing in a sandbox, and rollout with auditability. Applies the selected profile automatically based on the target matter or user selection at import time, ensuring CleanLift outputs meet the precise formatting expectations of local courts and downstream document templates.

Acceptance Criteria

Crosswalk Builder

Translates source picklists and statuses (e.g., Matter Stage, Relationship Roles, Outcome) into CaseSpark’s taxonomy with side‑by‑side value mapping. Prevents broken reports and inconsistent filters by enforcing required matches and testing against sample rows before you commit.

Requirements

Source Schema Discovery & Field Selection
"As a solo attorney configuring CaseSpark, I want CaseSpark to discover and list my source picklists and their distinct values so that I can confidently choose what to map without manually exporting or cleaning data."
Description

Enable ingestion of source picklists and status fields from supported inputs (CSV upload and API connectors to common practice-management systems). Automatically profile fields (datatype, distinct values, value counts, null rate), normalize whitespace/casing, and surface candidate fields such as Matter Stage, Relationship Roles, and Outcome. Provide a selector to include or exclude fields from the mapping session, with a live summary of discovered values. Cache discovery results per tenant with manual refresh and delta detection. Enforce data minimization by storing only enumerations and metadata, not full client PII. Outcome: a clean, curated set of source fields and values ready for crosswalk mapping.

Acceptance Criteria
Side-by-Side Mapping Workspace
"As an office manager, I want a fast, side-by-side interface with smart suggestions so that I can complete value mappings quickly and accurately without missing edge cases."
Description

Provide an interactive workspace that displays source values on the left and CaseSpark taxonomy values on the right, supporting drag-and-drop mapping, multi-select bulk mapping, keyboard shortcuts, and in-line search. Include auto-suggestions powered by fuzzy matching and jurisdiction-aware synonyms, with clear confidence indicators and one-click accept. Support many-to-one mappings when consolidating source values (e.g., multiple legacy stages to a single CaseSpark stage). Allow creation of new taxonomy values behind a permission gate with audit annotations. Persist drafts with autosave and show real-time mapping coverage metrics.

Acceptance Criteria
Required Match Enforcement & Validation
"As a practitioner, I want the system to prevent me from finalizing mappings with gaps or conflicts so that my reports and filters remain consistent after migration."
Description

Enforce completion rules before commit: all discovered source values must be mapped or explicitly marked with an approved fallback. Validate constraints such as duplicate mappings where disallowed, reserved taxonomy protections, and conflicting many-to-one rules. Provide a progress bar, error and warning panels with actionable fixes, and block finalization on critical errors while allowing documented exceptions on warnings. Emit a validation report for record-keeping and compliance.

Acceptance Criteria
Sample Row Test Runner & Preview Transform
"As a case intake coordinator, I want to preview how real records will look after applying the mapping so that I can catch mistakes before they affect live data."
Description

Allow users to run the draft mapping against a configurable set of sample rows drawn randomly or stratified by source value frequency. Present a side-by-side preview of source fields and their transformed CaseSpark outputs, flagging null results, unexpected fallbacks, and collisions. Provide inline navigation back to the mapping workspace to fix issues, and re-run tests quickly. Maintain performance safeguards and logging for traceability. Outcome: high confidence in the mapping before commit.

Acceptance Criteria
Commit, Versioning, and Rollback
"As a managing partner, I want versioned commits with easy rollback so that I can safely iterate on mappings and recover quickly if a change causes problems."
Description

On commit, create an immutable versioned crosswalk artifact with metadata (author, timestamp, source system, change summary). Provide a review-and-confirm screen with a diff from the prior version and optional approver workflow. Support instant rollback to any previous version without data loss and with re-propagation to dependent modules. Maintain a full audit trail for compliance and troubleshooting.

Acceptance Criteria
Impact Analysis & Report Integrity Check
"As a report owner, I want to know exactly which dashboards and filters will be affected before I commit a mapping so that I can prevent broken reporting for my team."
Description

Simulate the effects of the pending mapping on downstream CaseSpark artifacts, including saved filters, dashboards, automation rules, and document templates. Identify items that would break or change semantics, quantify affected matters, and propose remediation steps (e.g., replace deprecated values with mapped equivalents). Require a clean integrity check or explicit override with justification before commit. Provide a post-commit verification checklist.

Acceptance Criteria
Import/Export of Mapping Templates
"As an implementation specialist, I want to import and export mapping templates so that I can reuse proven crosswalks across clients and environments."
Description

Support export of crosswalks to portable JSON/CSV with schema and taxonomy version tags for portability across environments and tenants. Provide import with collision handling (merge, replace, skip), permission checks, and validation against the target tenant’s taxonomy. Offer a curated library of starter templates by practice area and jurisdiction to accelerate setup. Outcome: repeatable, shareable mappings that reduce onboarding time.

Acceptance Criteria

Dedupe Preview

Simulates merges before import using confidence scoring and clear “why” factors (alias, phone, address match). Lets you approve, split, or tune thresholds batch‑wide, preserving lineage and safe unmerge options—so you unify clients and matters without losing history or risking missed conflicts.

Requirements

Confidence Scoring Engine
"As an intake paralegal, I want each potential duplicate to have a clear, reliable confidence score so that I can prioritize my review and focus attention on the most likely matches."
Description

Compute a per-candidate duplicate likelihood score (0–100) using weighted signals across normalized identifiers (name and aliases, email, E.164 phone, USPS/CRA-normalized addresses with geocoding proximity, bar IDs, DOB, prior matter links). Provide configurable, firm-specific weighting profiles with deterministic scoring for repeatable runs and support locale/jurisdiction-aware normalization. Scale to large imports via streaming (target ≥100k records/hour) with low-latency scoring, and expose a pluggable rules layer for custom signals. Securely handle PII with tenant isolation and ensure model improvement via feedback from approve/split/skip outcomes.

Acceptance Criteria
Explainable Match Reasons Panel
"As an attorney, I want to see exactly why records are flagged as duplicates so that I can make defensible merge decisions and document my rationale."
Description

Present clear, human-readable ‘why’ factors for each suggested merge (e.g., alias match, normalized phone/email match, address proximity, docket/matter link, last activity) with strength indicators and exact field-level comparisons. Highlight mismatches and potential data quality issues, and allow drill-down to raw values without cross-tenant PII exposure. Ensure accessibility, printable summaries, and API parity so downstream systems can consume reasons alongside scores.

Acceptance Criteria
Batch Threshold Tuning & Live Preview
"As a firm admin, I want to adjust match thresholds and preview the results so that I can balance risk and efficiency before committing merges."
Description

Enable admins to set global and per-source thresholds for auto-merge, manual review, and auto-skip, with instant simulation of outcomes before import. Provide live counts, confidence histograms, risk indicators, and scenario comparisons (presets A/B). Persist threshold presets per import template, support role-based access, and ensure simulation mode performs no writes. Allow rollbacks of simulations and saving named presets for repeatable operations.

Acceptance Criteria
Approve/Split/Skip Decision Workflow
"As an intake specialist, I want quick controls to approve, split, or skip duplicates so that I can clear large batches accurately and efficiently."
Description

Provide a fast triage UI for batch review with actions to approve merge, split candidates into distinct entities, or skip. Support bulk actions by tag/reason, keyboard shortcuts, smart grouping (household/domain), pagination, and queue persistence. Display downstream impact (matters, filings, tasks) and block merges when conflict checks require attention. Implement optimistic concurrency and session undo, with full accessibility and performance targets suitable for high-volume review.

Acceptance Criteria
Lineage Preservation & Safe Unmerge
"As a managing partner, I want the ability to unmerge safely with full history so that mistakes can be corrected without compromising filings, conflicts, or client trust."
Description

On merge commit, record a complete lineage graph including source IDs, prior keys, import run, timestamps, decision maker, reasons viewed, and threshold preset. Perform non-destructive merges with reversible mappings and provide one-click unmerge to restore prior state and reattach child records. Enforce guardrails around filings and conflict history, require elevated permissions for sensitive unmerges, and ensure idempotency and auditability of all operations.

Acceptance Criteria
Conflict-Safe Simulation Integration
"As a conflicts coordinator, I want simulated merges to preserve and surface conflicts so that we never merge away or miss a potential conflict."
Description

Run conflict checks against the simulated merge graph during preview to ensure no action would mask or alter a potential conflict. Surface conflict risk badges, require explicit overrides with rationale, and generate a batch conflict report (PDF/CSV). Respect jurisdiction-specific rules and ethical walls, integrate with the existing CaseSpark conflict engine using read-only scope, and maintain triage latency under 250 ms per candidate.

Acceptance Criteria
Decision Audit Trail & Export
"As a compliance officer, I want a complete audit trail of deduplication decisions so that we can evidence defensible data handling during audits."
Description

Capture an immutable audit of all dedupe decisions and settings, including user, timestamp, before/after entities, reasons consulted, conflict outcomes, overrides, and comments. Provide search/filter, tenant-scoped access, export (CSV/PDF), and a webhook for post-run summaries. Support field redaction policies and align with SOC 2 logging standards and firm retention policies to meet compliance and discovery needs.

Acceptance Criteria

FileLift

Migrates attachments, PDFs, and images with original timestamps, authors, and matter links intact. Auto‑dedupes by hash, classifies common docs (IDs, orders, agreements), and places them in the right folders—saving hours of manual reattachment while keeping your audit trail clean.

Requirements

Universal Source Connectors
"As a solo attorney, I want FileLift to connect to my existing document sources so that I can migrate files without manually exporting and reuploading them."
Description

Enable FileLift to connect securely to common source systems (email, cloud storage, practice management tools, local/network drives) using OAuth and service accounts, discover eligible files, and stream them into CaseSpark without manual downloads. Support configurable scopes, throttling, source-side filtering, and incremental syncs to reduce load. Normalize metadata from heterogenous sources into a unified schema that downstream modules (dedupe, classification, audit) can consume, ensuring seamless end‑to‑end migrations.

Acceptance Criteria
Metadata Preservation & Mapping
"As a paralegal, I want original timestamps and authors to carry over so that our records remain accurate and defensible after migration."
Description

Capture and preserve original file metadata (created/modified timestamps, author/owner, source path, matter identifiers, checksums) and map it losslessly to CaseSpark’s data model. Handle timezone normalization, author identity resolution, and matter-link reconciliation so migrated documents retain provenance and appear in the correct matters. Validate mappings with preflight checks and provide a field-by-field mapping report for auditability.

Acceptance Criteria
Hash-based Deduplication
"As a firm owner, I want duplicates automatically removed or linked so that our repository stays clean and we don’t waste time managing the same document multiple times."
Description

Compute strong content hashes (e.g., SHA‑256) for all incoming files and compare against destination indexes to auto‑dedupe at matter and workspace scopes. Provide configurable dedupe policies (skip, link, replace) and a review queue for hash collisions and near‑duplicates detected via fuzzy matching. Emit a dedupe report showing retained, merged, and skipped files to prevent clutter and reduce storage while preserving traceability.

Acceptance Criteria
Smart Classification & Folder Routing
"As a legal assistant, I want documents auto‑sorted into the right matter folders so that I don’t spend hours reorganizing files after migration."
Description

Classify common legal documents (IDs, court orders, retainer agreements, pleadings, financial statements) using a hybrid rules+ML approach with confidence thresholds and human-in-the-loop review for low-confidence cases. Route files into standardized matter folder structures based on doc type, jurisdiction, and practice area, with configurable naming and templated folder schemes. Provide override rules and bulk re-route actions to correct misclassifications quickly.

Acceptance Criteria
Bulk Migration Wizard & Progress Tracking
"As an office manager, I want a step‑by‑step migration tool with clear progress and error reporting so that I can run large migrations confidently without disrupting daily work."
Description

Provide a guided, resumable migration wizard with preflight validation, dry‑run mode, and granular progress tracking (files processed, queued, skipped, errors). Support pause/resume, chunked transfers, backoff/retry on transient failures, and per-file error details with recommended fixes. Offer email and in‑app notifications on milestones and completion, plus exportable summaries for compliance and stakeholder updates.

Acceptance Criteria
Immutable Audit Trail & Chain‑of‑Custody
"As a compliance officer, I want an immutable audit trail of migration actions so that we can prove document provenance and satisfy audits or court inquiries."
Description

Record an immutable, tamper‑evident log of every migration event (who, what, when, source, destination, hash, action taken) with exportable reports for audits and e‑discovery. Support user attribution via SSO, time-synced entries, and cryptographic signatures of event batches. Provide searchable views and filters by matter, time range, and user to quickly resolve provenance questions and demonstrate defensible migration practices.

Acceptance Criteria

Rewind Diffs

Creates a snapshot for every import and shows side‑by‑side changes at contact, matter, and note level. Roll back an entire batch or selectively undo records with one click and an audit log—giving you stress‑free experimentation and instant recovery from mistakes.

Requirements

Import Snapshot Engine
"As a firm administrator, I want each import to be snapshotted automatically so that I can precisely restore data to its prior state if an import introduces errors."
Description

Automatically create an immutable, time-stamped snapshot for every import batch capturing pre- and post-state of contacts, matters, and notes at field level. Store snapshot metadata (actor, source file, import method, checksum, tenant, environment) and maintain referential integrity across related records. Assign a unique Snapshot ID per batch, support retention policies, encryption at rest/in transit, and cross-tenant isolation. Expose internal APIs/events for downstream services (search, conflict screening) to consume snapshot lifecycle changes. Ensure snapshots are write-once, versioned, and scalable to 100k+ records per batch with streaming writes and backpressure controls.

Acceptance Criteria
Side-by-Side Diff Viewer
"As an intake specialist, I want to see clear, side-by-side changes from an import so that I can quickly review and validate what was altered before deciding to undo anything."
Description

Provide an in-app, paginated diff viewer that displays side-by-side changes for contacts, matters, and notes with field-level highlights of added, modified, and deleted values. Support word-level diffs for long text (notes), masking/unmasking of sensitive fields, quick filters (entity type, change type, user, time), and search across changed fields. Include keyboard navigation, accessibility compliance, and mobile-responsive layouts. Show relationship deltas (e.g., contact-to-matter links) and indicate cascading effects. Maintain performance for large batches via server-side diffing, lazy loading, and caching.

Acceptance Criteria
Selective Rollback & Batch Restore
"As a paralegal, I want to undo only the records that were imported incorrectly so that I can fix mistakes without losing valid changes."
Description

Enable one-click rollback of an entire import batch or selective undo of specific records (contact, matter, note) from a snapshot. Provide a dry-run preview that summarizes the impact (records affected, relationships, potential conflicts) before execution. Execute rollbacks as atomic, idempotent transactions with retry logic, optimistic concurrency checks, and background job processing with progress indicators. After rollback, reindex search, refresh caches, and emit domain events for downstream consistency. Log partial failures with automatic remediation steps and allow safe re-run.

Acceptance Criteria
Permissioned Undo & Safeguards
"As a managing attorney, I want strict controls and approvals around rollbacks so that only authorized staff can reverse changes and we avoid accidental data loss."
Description

Gate rollback actions behind role-based access control and optional two-person approval for high-risk operations (e.g., >500 records or active matters). Require confirmation with a human-readable summary of changes, capture a mandatory reason, and enforce configurable time windows and rate limits for undo actions. Add guardrails for protected entities (e.g., filed matters) with warnings and policy overrides. Provide resumable operations, cancellation, and comprehensive error states to prevent data corruption or duplicate execution.

Acceptance Criteria
Tamper-Evident Audit Log & Export
"As a compliance officer, I want a tamper-evident log of all import changes and reversals so that I can demonstrate data integrity during audits or disputes."
Description

Record an immutable, append-only audit trail for each snapshot, diff view, and rollback including actor, timestamp, IP/device, Snapshot ID, affected record IDs, and before/after values. Use hash-chaining or equivalent to make tampering evident and store proofs. Provide filterable in-app views and export to CSV/PDF with pagination and redaction controls. Apply retention policies aligned with legal compliance and enable secure sharing with auditors via time-limited links. Integrate with the global activity feed and SIEM/webhook endpoints.

Acceptance Criteria
Conflict & Document Assembly Reconciliation
"As an attorney, I want conflicts and document drafts to reflect the latest data after an import or rollback so that I can rely on accurate risk checks and filings without manual rework."
Description

Automatically re-evaluate conflict screening indexes and update document assembly pipelines after imports and rollbacks. Recompute conflict flags, refresh deduplication and name matching, and re-run jurisdiction-aware templates if source data changed. Surface any new or cleared conflicts to users, update task/status boards, and notify relevant stakeholders. Ensure operations are idempotent, event-driven, and performance-aware to avoid reprocessing storms.

Acceptance Criteria

Sandbox Sync

Pushes dry‑runs into an isolated, clickable workspace where your team can validate searches, conflicts, and document assembly against real data. Supports scheduled cutover with delta import, so you test thoroughly, then go live without downtime or data drift.

Requirements

Isolated Sandbox Workspace Provisioning
"As a practice admin, I want to spin up an isolated sandbox mirroring production so that my team can test without risking live data or settings."
Description

Provision an isolated, production-parity workspace that receives dry-run pushes without any write-back to live systems. Support RBAC/SSO access controls, IP allowlists, environment tagging, and time-limited lifecycles with automatic cleanup. Enable seeding from a full or filtered production snapshot, preserve configuration parity (intake flows, conflict rules, templates), and provide environment health checks, activity logs, and secure, shareable links for reviewers.

Acceptance Criteria
Production Snapshot with Field-Level Masking
"As a compliance-conscious attorney, I want production data masked in sandbox so that we can validate with realistic records while protecting client privacy."
Description

Create a sandbox snapshot of production with configurable field-level masking that preserves referential integrity and searchability. Support masking templates (redaction, tokenization, hashing) for PII and sensitive fields while maintaining realistic data distributions for conflict checks and document assembly. Version control masking policies, enforce encryption in transit/at rest, honor data residency, and produce audit logs. Include freshness indicators and drift detection to alert when snapshots are stale.

Acceptance Criteria
Deterministic Conflict-Check Simulation
"As a paralegal, I want to simulate conflict checks in sandbox so that I can verify results and explanations match production before go-live."
Description

Execute the conflict engine in sandbox with the same rules, lists, and thresholds as production to produce deterministic, explainable outcomes. Provide step-by-step reasoning traces, side-by-side diffs against production results, and false positive/negative tagging for tuning. Support scenario builders (e.g., hypothetical parties, aliases, prior matters), performance metrics, and exportable result sets for review and sign-off.

Acceptance Criteria
Document Assembly Dry-Run Renderer
"As a template maintainer, I want to dry-run document assembly with jurisdiction rules so that errors are caught and outputs are verified before filing."
Description

Run jurisdiction-aware document assembly in sandbox and generate watermarked previews (PDF/DOCX) that show variable bindings, missing fields, and rule paths. Validate routing to court-specific templates, naming conventions, and e-sign placeholders. Allow template/version pinning, baseline comparisons, and downloadable artifacts for attorney review. Report merge errors and data gaps with actionable remediation guidance.

Acceptance Criteria
Delta Import & Cutover Scheduler
"As an operations manager, I want a scheduled cutover with delta import so that we can go live without downtime or data drift."
Description

Enable scheduled go-live with zero-downtime by computing and applying a delta change set from production since the sandbox snapshot. Include preflight validation, transactional/idempotent application, referential integrity checks, retries with backoff, and automatic rollback on failure. Provide time zone-aware scheduling, manual trigger, progress indicators, and notifications. Offer a dry-run of cutover steps and a final drift check before traffic switch.

Acceptance Criteria
Validation Dashboard & Traceable Reports
"As a team lead, I want a validation dashboard and exportable reports so that stakeholders can review evidence and approve cutover confidently."
Description

Provide a clickable sandbox dashboard summarizing test runs across searches, conflicts, and document assembly with pass/fail status, coverage, and timing. Offer diff views between sandbox and production, filters by matter/jurisdiction/template, and time-stamped traces. Support exportable PDF/CSV reports, shareable read-only links, webhooks for CI/CD, and an approval checklist that gates the cutover action.

Acceptance Criteria

Product Ideas

Innovative concepts that could enhance this product's value proposition.

Retainer Ready Checkout

Embed retainer/flat-fee payments into the e-sign flow with IOLTA-safe routing. Auto-collect ACH/card details, issue receipts, and set payment plans before the first hearing.

Idea

Role Lattice

Ship least‑privilege roles tuned for Solo, Orchestrator, and After‑Hours users. Toggle field‑level permissions and masked PII to prevent oversharing without slowing intake.

Idea

Conflict Graph Radar

Unify conflicts into a graph that links aliases, phones, emails, and household ties. Deliver sub‑second fuzzy matches and exact hits with an audit trail and false‑positive explainers.

Idea

Dual-Party Bridge

Run mirrored, non‑adversarial intakes for both spouses with conflict‑safe invites. Auto‑reconcile contradictions and merge shared facts into joint agreements and filings.

Idea

Text-to-Filing Sprint

Capture SMS, WhatsApp, and photo uploads into structured fields, then assemble e‑sign packets automatically. One tap sends court‑ready PDFs back for signature.

Idea

Jurisdiction Brain

Continuously track county‑level rule changes, filing fees, and clause variants. Flag outdated templates and auto‑suggest the correct paragraph or form revision at assembly time.

Idea

Zero-Drag Migration

Import contacts, matters, and notes from spreadsheets or Clio with a dry‑run validator and rollback. Family‑law field‑mapping presets accelerate clean, accurate onboarding.

Idea

Press Coverage

Imagined press coverage for this groundbreaking product concept.

Want More Amazing Product Ideas?

Subscribe to receive a fresh, AI-generated product idea in your inbox every day. It's completely free, and you might just discover your next big thing!

Product team collaborating

Transform ideas into products

Full.CX effortlessly brings product visions to life.

This product was entirely generated using our AI and advanced algorithms. When you upgrade, you'll gain access to detailed product requirements, user personas, and feature specifications just like what you see below.