The Ontology Collaboration Loop
The ontology is the case's understanding; the graph is only its data — and it
can be wrong or incomplete. Your job (as counsel, see relex-counsel) is to
audit that understanding, repair it, and direct the Relex harness to acquire what
is missing. The harness's next reasoning turn automatically reads what you fixed.
read → audit → repair/enrich → direct acquisition → agent re-reasons → re-read → converge
Everything below is PII-safe by construction: people appear only as
[PARTY_NAME_n] label tokens; fact entities carry keys, never values. The
server's PII gate rejects raw identifiers you might try to write — don't.
1 · Read
execute GET /ontology/case/{caseId} — the case graph: real-world legal
objects (parties, obligations, clauses, statutes, events, ISSUES) and the
verbs binding them (cites, concerns, supports, contradicts,
undercuts, party_to, raises, established_by).
execute GET /ontology/firm (?scope=org&id= for an org) — the practice's
abstract concept graph (doctrines, clause types, argument patterns), grown
automatically from knowledge uploads and concluded cases. No case instances,
no PII. ANY org member can read the org graph; only curation is admin-gated.
If the graph is sparse but the practice HAS indexed knowledge, backfill it:
POST /ontology/firm/reconcile (self / org-admin) — call repeatedly until
the response's remaining is 0 (each call processes up to 25 sources).
- Read the case itself too (
GET /cases?caseId={caseId}&full=true — caseId is a
query param; full=true is REQUIRED to get the timeline/phases, a plain
GET /cases returns a bounded summary): timeline, phases, locked
issues, drafts. The graph must MATCH the case data — mismatch is a finding.
2 · Audit — formal conflicts first, then the gap taxonomy
The system audits with you. Every ontology read carries conflicts[] —
formal integrity findings the platform derives fresh from the graph on every
read (never stored, so never stale): unresolved contradicts/undercuts
edges, claims resting on ALLEGED facts, ungrounded claims, deadlines without
date or trigger, obligations without obligor, open issues with no acquisition
plan, duplicates, low-confidence structure, entities flagged stale, and a
whole-graph staleness flag when case data changed after the last ontology
update. The digest view and your steering block (steering.conflicts) carry
the top findings; ?view=full (or the plain GET) has the complete list with
resolution hints. The user sees the SAME list in the case UI.
Work them symbiotically: resolve each conflict via §3 ops (settle/contest
the issue, add the missing link/date/party, merge duplicates, re-verify and
clear a stale flag) — and contribute conflicts the formal checks cannot
see: when YOU spot a semantic contradiction, add the contradicts/undercuts
edge; when something presupposes outdated law, set properties.stale=true on
it. The moment you write it, the system formalizes your finding and shows it
to the user and the internal agent too. Never leave a conflict silently
unaddressed: resolve it, acquire what resolves it, or escalate both sides to
the human.
The gap taxonomy
Walk the graph against the case facts. For each gap type there is one correct
acquisition verb — never fill a gap from model memory:
| Gap |
Signal |
Directive |
| Grounding |
an issue/claim cites no statute, or cites one with no cached verbatim text |
POST /research/scrape (see relex-research) |
| Coverage |
a fact pattern with no enumerated candidate issue at all |
steer a re-reason turn: POST /agent {type:"case_req", …} naming the un-covered pattern |
| Entity |
an actor appears in the timeline/docs but not as a [PARTY_NAME_n] node |
user finishes pending parties in the browser (deep link) or id-only attach |
| Evidence |
a fact asserted with no source document |
deep-link the user to upload; or search knowledge via the agent |
| Conflict |
contradicts/undercuts edges nobody resolved |
acquire the resolving authority, or escalate to the human with both sides |
| Temporal |
timeline holes around dispositive events |
ask the user ONE targeted question (question-brake, relex-counsel) |
| Currency |
statute possibly amended / transposition pending |
re-scrape the latest version before relying on it |
3 · Repair / enrich
execute POST /ontology/case/{caseId}/agent with a natural-language
instruction; the editor turns it into typed, transactional, PII-gated ops
(upsert, merge, link, retype, set issue status):
execute({ method: "POST", path: "/ontology/case/abc123/agent", body: { message:
"Add issue 'limitation period' status=contested; link it as undercutting the
payment claim; merge the duplicate 'Delivery Contract' entities; the
[PARTY_NAME_2] node is the addressee institution — retype it authority." } })
Rules:
- Write only what case data or verified sources support — never model memory.
- ISSUES carry status
open | contested | settled. Mark settled only when
grounded (cached verbatim text or a user-confirmed fact) — say the ground in
the instruction so it lands in the graph.
- After big case-state changes,
POST /ontology/case/{caseId}/reconcile rebuilds
the deterministic backbone (additive; your edits survive), then re-read.
- Curate reusable patterns (clause types, argument shapes — nothing
case-specific) into the firm graph:
POST /ontology/firm/agent.
4 · Direct acquisition
You discover; the harness fetches-and-caches (division of labour —
relex-research has the full doctrine):
GET /research/sources — what the harness can fetch verbatim vs discovery-only.
POST /research/scrape {jurisdiction, code, article, authorityType, sourceHint?, caseId?}
— cache one authority's verbatim text. Poll GET /research/scrape/{jobId}.
POST /agent {type:"case_req", caseId, payload:{prompt}} — steer the case
agent: name the issues to (re)enumerate, the knowledge to search, the parties
that matter. It reads the updated ontology automatically and emits its own
scrape needs for anything still missing. These are steering-session turns on
your private steering branch (relex-steering has the protocol); the reply's
steering.missing_data maps directly onto the §2 gap taxonomy — treat each
item as a gap with its acquisition verb (or its browser deep link).
5 · Converge — and say so
The loop is done when:
- every locked/settled issue is verbatim-grounded,
- every open issue has an acquisition plan (directive issued, question
asked, or escalated),
- no unresolved
contradicts/undercuts edge remains without a human flag,
- addressee and deadlines are locked in the case data.
Record the state as a short Votum (interim vote) on the case via a
case_req message — e.g. "Ontology audit: 6 issues grounded, 1 contested
(limitation — directive pending job 4f2c), no open conflicts; addressee locked.
Next: re-reason after ingest." Interim Vota land on the steering branch;
capture the convergence state in the session's conclude summary
(relex-steering) so it propagates to the main thread. Report progress to the
user with counts and labels only — never names.
Anti-patterns
- Filling a graph gap from memory ("I know Art. 823 says…") — that's a
grounding gap, not knowledge. Issue the directive.
- Re-doing the harness's work: you never scrape, never RAG-search private
corpora yourself, never re-implement its reasoning directive.
- Overwriting agent-locked issues without evidence — repair with grounds, or
contest with an
undercuts edge and acquire.
- Big-bang rewrites of the graph. Small typed ops, then re-read.
1---2name: relex-ontology3description: Use when working a Relex case beyond a single question — auditing what the case "understands", finding gaps or contradictions in the case/firm ontology graph, steering the Relex case agent, or deciding what data to acquire next (RAG, statutes, case law, documents). Teaches the read → audit → repair → direct-acquisition → converge loop over the Relex MCP.4---56# The Ontology Collaboration Loop78The ontology is the case's **understanding**; the graph is only its data — and it9can be **wrong or incomplete**. Your job (as counsel, see `relex-counsel`) is to10audit that understanding, repair it, and direct the Relex harness to acquire what11is missing. The harness's next reasoning turn automatically reads what you fixed.1213```14read → audit → repair/enrich → direct acquisition → agent re-reasons → re-read → converge15```1617Everything below is PII-safe by construction: people appear only as18`[PARTY_NAME_n]` label tokens; fact entities carry keys, never values. The19server's PII gate rejects raw identifiers you might try to write — don't.2021## 1 · Read2223- `execute GET /ontology/case/{caseId}` — the case graph: real-world legal24 objects (parties, obligations, clauses, statutes, events, ISSUES) and the25 verbs binding them (`cites`, `concerns`, `supports`, `contradicts`,26 `undercuts`, `party_to`, `raises`, `established_by`).27- `execute GET /ontology/firm` (`?scope=org&id=` for an org) — the practice's28 abstract concept graph (doctrines, clause types, argument patterns), grown29 automatically from knowledge uploads and concluded cases. No case instances,30 no PII. ANY org member can read the org graph; only curation is admin-gated.31 If the graph is sparse but the practice HAS indexed knowledge, backfill it:32 `POST /ontology/firm/reconcile` (self / org-admin) — call repeatedly until33 the response's `remaining` is 0 (each call processes up to 25 sources).34- Read the case itself too (`GET /cases?caseId={caseId}&full=true` — caseId is a35 query param; `full=true` is REQUIRED to get the timeline/phases, a plain36 `GET /cases` returns a bounded summary): timeline, phases, locked37 issues, drafts. The graph must MATCH the case data — mismatch is a finding.3839## 2 · Audit — formal conflicts first, then the gap taxonomy4041**The system audits with you.** Every ontology read carries `conflicts[]` —42formal integrity findings the platform derives fresh from the graph on every43read (never stored, so never stale): unresolved `contradicts`/`undercuts`44edges, claims resting on ALLEGED facts, ungrounded claims, deadlines without45date or trigger, obligations without obligor, open issues with no acquisition46plan, duplicates, low-confidence structure, entities flagged stale, and a47whole-graph staleness flag when case data changed after the last ontology48update. The digest view and your steering block (`steering.conflicts`) carry49the top findings; `?view=full` (or the plain GET) has the complete list with50`resolution` hints. The user sees the SAME list in the case UI.5152Work them symbiotically: **resolve** each conflict via §3 ops (settle/contest53the issue, add the missing link/date/party, merge duplicates, re-verify and54clear a stale flag) — and **contribute** conflicts the formal checks cannot55see: when YOU spot a semantic contradiction, add the `contradicts`/`undercuts`56edge; when something presupposes outdated law, set `properties.stale=true` on57it. The moment you write it, the system formalizes your finding and shows it58to the user and the internal agent too. Never leave a conflict silently59unaddressed: resolve it, acquire what resolves it, or escalate both sides to60the human.6162### The gap taxonomy6364Walk the graph against the case facts. For each gap type there is one correct65acquisition verb — never fill a gap from model memory:6667| Gap | Signal | Directive |68|---|---|---|69| **Grounding** | an issue/claim cites no statute, or cites one with no cached verbatim text | `POST /research/scrape` (see `relex-research`) |70| **Coverage** | a fact pattern with no enumerated candidate issue at all | steer a re-reason turn: `POST /agent {type:"case_req", …}` naming the un-covered pattern |71| **Entity** | an actor appears in the timeline/docs but not as a `[PARTY_NAME_n]` node | user finishes pending parties in the browser (deep link) or id-only attach |72| **Evidence** | a fact asserted with no source document | deep-link the user to upload; or search knowledge via the agent |73| **Conflict** | `contradicts`/`undercuts` edges nobody resolved | acquire the resolving authority, or escalate to the human with both sides |74| **Temporal** | timeline holes around dispositive events | ask the user ONE targeted question (question-brake, `relex-counsel`) |75| **Currency** | statute possibly amended / transposition pending | re-scrape the latest version before relying on it |7677## 3 · Repair / enrich7879`execute POST /ontology/case/{caseId}/agent` with a natural-language80instruction; the editor turns it into typed, transactional, PII-gated ops81(upsert, merge, link, retype, set issue status):8283```84execute({ method: "POST", path: "/ontology/case/abc123/agent", body: { message:85 "Add issue 'limitation period' status=contested; link it as undercutting the86 payment claim; merge the duplicate 'Delivery Contract' entities; the87 [PARTY_NAME_2] node is the addressee institution — retype it authority." } })88```8990Rules:91- Write only what case data or **verified** sources support — never model memory.92- ISSUES carry status `open | contested | settled`. Mark `settled` only when93 grounded (cached verbatim text or a user-confirmed fact) — say the ground in94 the instruction so it lands in the graph.95- After big case-state changes, `POST /ontology/case/{caseId}/reconcile` rebuilds96 the deterministic backbone (additive; your edits survive), then re-read.97- Curate reusable patterns (clause types, argument shapes — nothing98 case-specific) into the firm graph: `POST /ontology/firm/agent`.99100## 4 · Direct acquisition101102You discover; the harness fetches-and-caches (division of labour —103`relex-research` has the full doctrine):104105- `GET /research/sources` — what the harness can fetch verbatim vs discovery-only.106- `POST /research/scrape {jurisdiction, code, article, authorityType, sourceHint?, caseId?}`107 — cache one authority's verbatim text. Poll `GET /research/scrape/{jobId}`.108- `POST /agent {type:"case_req", caseId, payload:{prompt}}` — steer the case109 agent: name the issues to (re)enumerate, the knowledge to search, the parties110 that matter. It reads the updated ontology automatically and emits its own111 scrape needs for anything still missing. These are steering-session turns on112 your private steering branch (`relex-steering` has the protocol); the reply's113 `steering.missing_data` maps directly onto the §2 gap taxonomy — treat each114 item as a gap with its acquisition verb (or its browser deep link).115116## 5 · Converge — and say so117118The loop is done when:1191. every locked/settled issue is **verbatim-grounded**,1202. every open issue has an **acquisition plan** (directive issued, question121 asked, or escalated),1223. no unresolved `contradicts`/`undercuts` edge remains without a human flag,1234. addressee and deadlines are locked in the case data.124125Record the state as a short **Votum** (interim vote) on the case via a126`case_req` message — e.g. *"Ontology audit: 6 issues grounded, 1 contested127(limitation — directive pending job 4f2c), no open conflicts; addressee locked.128Next: re-reason after ingest."* Interim Vota land on the steering branch;129capture the convergence state in the session's **conclude summary**130(`relex-steering`) so it propagates to the main thread. Report progress to the131user with counts and labels only — never names.132133## Anti-patterns134135- Filling a graph gap from memory ("I know Art. 823 says…") — that's a136 **grounding gap**, not knowledge. Issue the directive.137- Re-doing the harness's work: you never scrape, never RAG-search private138 corpora yourself, never re-implement its reasoning directive.139- Overwriting agent-locked issues without evidence — repair with grounds, or140 contest with an `undercuts` edge and acquire.141- Big-bang rewrites of the graph. Small typed ops, then re-read.