- Documentation
- /
- Clo
- /
- Phase 2 — Runtime Engine Scope
Phase 2 — Runtime Engine Scope
Phase 1 (built) renders the 19-model schema as an AI-Safe CRUD register: requests,
matters, issues, tasks, risks, decisions, approvals, engagements, spend, documents,
SLAs and knowledge — browsable, with a dashboard. But the states are static:
the seed shows a request already converted_to_matter, an SLA already on_track,
spend already invoiced. Nothing is computed, timed or transitioned by the
system.
Phase 2 is the runtime that makes it live — running the SLA clocks, enforcing the state machines, controlling spend against budget, and applying the intake / privilege / approval rules the pack specifies. Same shape as the (built, cluster-proven) orchestrator engine, but single-app.
Everything below is drawn from the pack's workflows.yaml, rules.yaml, the DSL
derived {} blocks and the LegalOperationsDashboard. It is a scope, not a design.
A. Derived-field & rollup engine
Seeded statically today; Phase 2 computes them:
| Field | Rule |
|---|---|
LegalRequest.days_to_required / overdue |
vs required_by, excluding closed/cancelled/converted |
LegalMatter.days_open |
opened_date → closed_date (or today) |
LegalMatter.net_exposure |
estimated_exposure − estimated_recovery |
MatterTask.overdue |
past due_date and not completed/cancelled |
Plus spend rollups: total SpendEntry.total_amount per matter (by status) vs
LegalMatter.budget — the input to over-budget detection and the dashboard.
B. State machines & guarded actions
The pack defines five workflows with transitions, guards and side-effects.
Today a user free-edits status; Phase 2 exposes each as a guarded action.
| Workflow | Notable guards & effects |
|---|---|
| legal_request (draft→submitted→triage→accepted→converted_to_matter) | submit requires the core fields and creates the SLA; accept assigns the legal owner; convert_to_matter creates the matter and links it |
| legal_matter (draft→open→active→…→resolved→closed) | resolve requires outcome + outcome_summary; close closes open tasks and prompts knowledge capture |
| counsel_engagement (proposed→conflict_check→approved→engaged→active→completed) | approve requires conflict check complete + approver + budget; engage requires scope + fee arrangement |
| legal_decision (draft→under_review→approved→implemented) | approve stamps the decision date + emits; implement stamps implemented |
| approval (pending→approved/rejected/withdrawn) | stamps responded_at, emits the result |
Decisions: UI buttons vs API; role → PIN/RBAC; auto-actions (create SLA/matter) vs manual.
C. The SLA engine
The headline runtime — turns ServiceLevel targets into live, pausable clocks
(SLAInstance), the thing that makes a legal-ops function measurable:
- On request submit, create an
SLAInstancefrom the matchingServiceLeveland computefirst_response_due_at/triage_due_at/resolution_due_at. - A tick moves the instance through
on_track → due_soon → overdue, marksfirst_response_at/triage_completed_at/resolved_at, and setsmet/breached. - Pause when awaiting the business (
ServiceLevel.pause_when_awaiting_business) — accumulatepaused_minuteswhile the matter/request isawaiting_business.
Decisions: the business-calendar / working-hours model (targets are in
hours/days — the pack ships business_calendars.yaml); tick cadence; which events
stop the clock.
D. Rules / cross-record automation
From rules.yaml — intake, spend and governance guardrails:
- Intake — a
criticalrequest → notify GC (legal.request.critical); anurgent/criticalsubmitted request → auto-assign a triage owner; a request pastrequired_by(hourly) → emit overdue + notify the assigned lawyer. - Spend control — matter spend over
budget→ emitbudget_exceeded+ notify owners; aninvoicedentry ≥ $10,000 requires approval. - Counsel — an
externalproposed engagement requires approval; a non-panel firm requires an exception approval. - Privilege gate — a
MatterDocumentmoving toissuedwhile privilege is unresolved is blocked ("resolve privilege before external issue"). - Governance — a matter cannot
closewhile a critical residual risk is open; anapproveddecision past its implementation date (daily) notifies the owner; aKnowledgeItemwithin 30 days ofreview_date(daily) notifies the owner. - Critical matter — a
criticalmatter notifies the GC.
Decisions: event bus (in-app vs orchestrator); block vs flag; notify channel; how "auto-assign triage" picks an owner.
E. Legal-operations dashboard & KPIs
The DSL LegalOperationsDashboard, wired via the repo KPI framework
(kpi_engine.py + kpis.py):
- Metrics: open requests; open matters; critical matters; overdue tasks; pending approvals; outside-counsel spend YTD; matters over budget; overdue requests.
- Sections: intake queue; high-risk matters; workload by lawyer; spend by firm; spend by matter type; SLA performance; pending decisions; upcoming deadlines.
How it would be built
- A per-app engine module (mirror
server/lib/orchestrator_engine/): compute pass + spend rollups (A), the SLA engine/tick (C), guarded actions (B), rules evaluator (D). Opt-in env flag, single worker. - KPIs (E) via the existing framework — quick, independent win (and the spend/SLA metrics are the ones a GC actually wants).
- Business-calendar / working-hours underpins the SLA clocks and deadlines.
- Tests per workstream (
test_orchestrator_flows.pyis the template).
Suggested sequencing
- KPIs / dashboard (E) — visible, no engine; the spend + SLA numbers are the headline.
- Derived fields + spend rollups (A) — makes over-budget / overdue real.
- SLA engine (C) — the measurable-service core; needs the working-hours calendar.
- Spend & governance rules (D) — budget, approval and privilege guardrails.
- State machines + guards (B) — governed intake → matter → resolution.
Each slice is independently shippable and demoable. The orchestrator (built and run live this session) is the working template for the engine, scheduler and tests.