Audit the Patient Graph
Walk the graph endpoints to trace a fact back to its extracted facts, read why a pair did or did not merge, and review what a patient said against the chart.
Trace a fact to the extracted facts behind it
A fact shows one value. Find out which extracted facts it rests on and what each of them stated.
- Find the fact:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/{patientId}/graph/nodes/fact/items?perPage=1000" \
-H "Authorization: Bearer <access-token>"- Walk
resolves_tobackwards to its members. Each edge runsextracted_fact → fact:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/{patientId}/graph/edges/resolves_to/items?touching={factId}" \
-H "Authorization: Bearer <access-token>"- Open each extracted fact to see what its own source stated:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/{patientId}/graph/nodes/extracted_fact/items/{extractedFactId}" \
-H "Authorization: Bearer <access-token>"The fact carries only the winning value; each extracted fact keeps the dates, status and codes its source stated, so the comparison is between the extracted facts, one request each.
See why two extracted facts merged
The same walk, one edge further: the pair's verdict.
Pass both extracted fact ids as touching to get the single resolution decision across that pair:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/{patientId}/graph/edges/resolution_decision/items?touching={idA}&touching={idB}" \
-H "Authorization: Bearer <access-token>"payload.verdict is merge, payload.ruleId names the stop rule that fired (deterministic-code-exact), and payload.evidence carries what each cascade layer compared.
See why two facts did not merge
Two entries that read as the same thing are two facts, so the walk starts from both and meets in the middle.
- List the facts and pick the pair — two of the same
payload.typethat describe the same thing:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/{patientId}/graph/nodes/fact/items?perPage=1000" \
-H "Authorization: Bearer <access-token>"- Expand each fact to its extracted facts, one request per fact:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/{patientId}/graph/edges/resolves_to/items?touching={factId}" \
-H "Authorization: Bearer <access-token>"- Ask for the decision across one extracted fact from each side. This is the leg that crosses between the two facts, so it is the one that refused them:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/{patientId}/graph/edges/resolution_decision/items?touching={idA}&touching={idB}" \
-H "Authorization: Bearer <access-token>"payload.verdict is reject. payload.ruleId names the rule that refused the pair.
The decision can also be fetched on its own if the id is known.
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/{patientId}/graph/edges/resolution_decision/items/{edgeId}" \
-H "Authorization: Bearer <access-token>"See why two narratives did not merge
Narratives resolve at the passage level, so the decision sits between two narrative passages rather than between the extracted narratives they were chunked from.
- List the extracted narratives — one per block of free-form text the sources carried:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/{patientId}/graph/nodes/extracted_narrative/items?perPage=1000" \
-H "Authorization: Bearer <access-token>"- Walk
chunked_intofrom each to its passages. Each edge runsextracted_narrative → narrative_passage:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/{patientId}/graph/edges/chunked_into/items?touching={extractedNarrativeId}" \
-H "Authorization: Bearer <access-token>"- Ask for the decision across one passage from each side:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/{patientId}/graph/edges/resolution_decision/items?touching={passageA}&touching={passageB}" \
-H "Authorization: Bearer <access-token>"A recorded reject reads like the fact case with the embedding layer in place of the codes: payload.ruleId is narrative-cosine-reject-at-or-below-low, and the narrative-semantic-similarity evidence carries the cosine measurement — the similarity itself, and the mergeAtOrAbove / rejectAtOrBelow bounds it was read against.
When no decision was recorded at all
Often the answer is empty — data is [] and meta.total is 0. Two different things produce it, and the endpoint cannot tell them apart:
- The pair was deferred. Its similarity fell between the two bounds, the system was not confident enough to settle a decision.
- The pair was never compared. Each passage is only ranked against a set number of candidates, and a pair outside that set is never evaluated.
Settling the deferred band is on the roadmap
A further step that decides the pairs falling between the bounds, rather than leaving them open, is planned. Once it lands, a pair that was compared carries a decision either way, and an empty answer narrows to the second case.
Review what the patient said against the chart
Contradictions between a learned memory and a fact are relationship edges, so the whole inbox is one query:
curl -X POST "https://<workspace-id>.w.clinia.cloud/v1/patients/{patientId}/graph/edges/relationship/query" \
-H "Authorization: Bearer <access-token>" \
-H "Content-Type: application/json" \
-d '{ "perPage": 1000, "filter": { "type": { "eq": "conflicts" } } }'Each edge runs learned_memory → fact and says why it was drawn without leaving the edge: payload.source is llm_inferred, and payload.attributes.fields names the fields it conflicts on.
Open from for what the patient said — payload.content is their own words, payload.sessionId the session it was said in, and the node's createdAt when:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/{patientId}/graph/nodes/learned_memory/items/{memoryId}" \
-H "Authorization: Bearer <access-token>"Open to for the fact it contradicts, which carries the value the chart still holds:
curl "https://<workspace-id>.w.clinia.cloud/v1/patients/{patientId}/graph/nodes/fact/items/{factId}" \
-H "Authorization: Bearer <access-token>"