Add a bounded relation graph and knowledge journeys.
CONTENT-WP-0004 keeps outgoing and incoming labels apart, limits the graph to two hops, and stores focus and detail in the URL. Assistant: grok Assistant-Session: 01a1531b-6698-7732-8587-f28ea604bcdf
This commit is contained in:
parent
749752df4e
commit
b5b6f6bc00
15 changed files with 1290 additions and 52 deletions
|
|
@ -4,19 +4,19 @@ type: workplan
|
|||
title: "Relation explorer and knowledge journeys"
|
||||
domain: infotech
|
||||
repo: content-explorer
|
||||
status: proposed
|
||||
status: finished
|
||||
flavor: implementation
|
||||
depends_on:
|
||||
- CONTENT-WP-0002
|
||||
- CONTENT-WP-0003
|
||||
created: "2026-10-12"
|
||||
updated: "2026-10-12"
|
||||
updated: "2026-10-19"
|
||||
state_hub_workstream_id: "d78fa2e0-9052-5e3b-93b6-e8c86248bad1"
|
||||
---
|
||||
|
||||
# Relation explorer and knowledge journeys
|
||||
|
||||
Make interconnected knowledge explorable beyond the basic browse and detail path.
|
||||
Make interconnected knowledge explorable beyond the basic browse and detail path. T01 through T08 are done. See `workplans/evidence/CONTENT-WP-0004-ImplementationNotes.md` and `workplans/evidence/CONTENT-WP-0004-Review.md`.
|
||||
|
||||
## Work packages
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ Make interconnected knowledge explorable beyond the basic browse and detail path
|
|||
|
||||
```task
|
||||
id: CONTENT-WP-0004-T01
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "e64d9cdd-10ee-5a6e-b714-76037ca8bacc"
|
||||
```
|
||||
|
|
@ -33,7 +33,7 @@ state_hub_task_id: "e64d9cdd-10ee-5a6e-b714-76037ca8bacc"
|
|||
|
||||
```task
|
||||
id: CONTENT-WP-0004-T02
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "78c2c68d-fe5c-532e-892d-73939d647bbe"
|
||||
```
|
||||
|
|
@ -42,7 +42,7 @@ state_hub_task_id: "78c2c68d-fe5c-532e-892d-73939d647bbe"
|
|||
|
||||
```task
|
||||
id: CONTENT-WP-0004-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "fad1f2fb-0f97-5512-88ae-dff430004811"
|
||||
```
|
||||
|
|
@ -51,7 +51,7 @@ state_hub_task_id: "fad1f2fb-0f97-5512-88ae-dff430004811"
|
|||
|
||||
```task
|
||||
id: CONTENT-WP-0004-T04
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "274e7a5b-ce17-51c6-a073-6945b9a34ff8"
|
||||
```
|
||||
|
|
@ -60,7 +60,7 @@ state_hub_task_id: "274e7a5b-ce17-51c6-a073-6945b9a34ff8"
|
|||
|
||||
```task
|
||||
id: CONTENT-WP-0004-T05
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "edf84d8c-8913-544a-9f39-3ef1d8a99468"
|
||||
```
|
||||
|
|
@ -71,7 +71,7 @@ state_hub_task_id: "edf84d8c-8913-544a-9f39-3ef1d8a99468"
|
|||
|
||||
```task
|
||||
id: CONTENT-WP-0004-T06
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "d582553b-3966-55e0-b294-85d6cb42e516"
|
||||
```
|
||||
|
|
@ -80,7 +80,7 @@ state_hub_task_id: "d582553b-3966-55e0-b294-85d6cb42e516"
|
|||
|
||||
```task
|
||||
id: CONTENT-WP-0004-T07
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "61d43835-8da7-5af3-9368-c3aa3120f486"
|
||||
```
|
||||
|
|
@ -89,7 +89,7 @@ state_hub_task_id: "61d43835-8da7-5af3-9368-c3aa3120f486"
|
|||
|
||||
```task
|
||||
id: CONTENT-WP-0004-T08
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "018814db-3aab-5fd2-bebf-8e4c7d7047d2"
|
||||
```
|
||||
|
|
|
|||
59
workplans/evidence/CONTENT-WP-0004-ImplementationNotes.md
Normal file
59
workplans/evidence/CONTENT-WP-0004-ImplementationNotes.md
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
# CONTENT-WP-0004 implementation notes
|
||||
|
||||
Date: 2026-10-19
|
||||
|
||||
Hop bound: 2 (`HOP_BOUND` in `ui/lib/graph.ts`). A requested distance above 2 is clamped. Neighborhood walks are undirected. Each edge keeps its stored `from`, `to`, predicate, and id.
|
||||
|
||||
Journey fields did not require a schema bump. Manifest and snapshot 0.1 still set `additionalProperties: false` at the document root, and entity `properties` is already an open object. Collections, related ids, reading paths, glossary text, and link previews live there. Today's fixtures still validate.
|
||||
|
||||
## T01 — outgoing and incoming blocks
|
||||
|
||||
`partitionIncident` places every relation that touches an entity in exactly one block. Outgoing wording is the manifest forward label. Incoming wording is the inverse label. A self-loop is outgoing. `EntityDetail` renders the two blocks separately. When a caller lists only part of the incident set, `relationRemainder` is shown as “N more relations are not listed.”
|
||||
|
||||
Systems-thinking Feedback uses forward “Represented by” on `represented-by`. The incoming `models` edge uses “Modeled by”, which is not the forward string “Models”.
|
||||
|
||||
## T02 and T05 — bounded graph
|
||||
|
||||
`selectNeighborhood` returns the focus plus nodes within the hop bound. Cycles stop because each node is visited once. Parallel edges stay as separate adjacency records (`id`, `predicate`, `from`, `to`, `direction: "out"`). Both parents of a node stay. A node with no edges remains in the graph model and can be focused. The route is `/{dataspace}/graph?focus=<entity id>&detail=<entity id>&hops=1`. Hop 2 omits `hops`. The page shows the excluded-relation count.
|
||||
|
||||
## T03 — collections, related objects, reading paths
|
||||
|
||||
A declared `properties.collection` lists member links. `properties.related` lists related objects. `properties.readingPath` is rendered in that order. The crumb for the open entity is the current step. Each earlier crumb is a link to that step.
|
||||
|
||||
Feedback declares the collection “Ways to draw feedback”, a related link to Emergence, and the path System boundary → Feedback → Causal loop diagram.
|
||||
|
||||
## T04 — glossary and previews
|
||||
|
||||
`RecordLink` shows a glossary tooltip only when the target has `properties.glossary`, and a preview only when `properties.preview` has both a title and a summary. Causal loop diagram has both. Stock and flow model has neither: its link still resolves, and the page does not render a tooltip or preview for it. System boundary has no journey properties and still renders.
|
||||
|
||||
## T06 — nothing incident is silent
|
||||
|
||||
The Feedback page lists every incident relation id from the snapshot in exactly one block. The graph page prints the count of relations outside the neighborhood.
|
||||
|
||||
## T07 — focus and detail in the URL
|
||||
|
||||
`GraphExplorer` reads and writes `focus` and `detail` through the same history helper the page uses in the browser. Reload passes the query back in as `initialSearch`. Back and forward restore the previous focus and detail. Covered in `ui/components/GraphExplorer.history.test.tsx`.
|
||||
|
||||
## T08 — synthetic fixture
|
||||
|
||||
`ui/fixtures/large-graph.json` is a chain `n0`–`n8` (8 edges) plus an isolated node `solo`. It is a test fixture, not a published dataspace, so `validate_fixtures.py` still checks only the two example dataspaces.
|
||||
|
||||
From `n0` at hop bound 2, the neighborhood is `n0`, `n1`, and `n2`. `n8` is outside. `excludedCount` is 6, equal to the edges that do not have both ends inside that neighborhood. Focusing `solo` returns that node and excludes all 8 edges.
|
||||
|
||||
## Checks
|
||||
|
||||
Durable tests:
|
||||
|
||||
- `ui/lib/graph.test.ts`
|
||||
- `ui/components/EntityDetail.test.tsx`
|
||||
- `ui/components/GraphExplorer.history.test.tsx`
|
||||
|
||||
Captured on 2026-10-19 under `/tmp/grok-goal-aedf5fe6975e/implementer/`:
|
||||
|
||||
- `ui-test-1.txt` and `ui-test-2.txt`: `npm test` in `ui/`, 11 files, 32 tests, both exit 0.
|
||||
- `typecheck.txt`: `npm run typecheck` in `ui/`, exit 0.
|
||||
- `fixtures.txt`: `python3 scripts/validate_fixtures.py`, `python3 -m unittest tests.test_contract tests.test_ingest`, and `python3 scripts/check_ui_boundary.py`, exit 0.
|
||||
- `launch-1.html` and `launch-2.html`: HTTP 200 for `/systems-thinking/graph?focus=urn:ce:systems-thinking:concept:feedback`. Both bodies contain “Represented by” and “Modeled by”.
|
||||
- `graph.png`: headless Chromium loaded that URL with no page error. Focusing Causal loop diagram changed the neighborhood and the `focus` query. The screenshot is not blank.
|
||||
|
||||
No R6 deviation. The safeguard is the hop bound of 2, not a graph database or a draw-everything view.
|
||||
11
workplans/evidence/CONTENT-WP-0004-Review.md
Normal file
11
workplans/evidence/CONTENT-WP-0004-Review.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# CONTENT-WP-0004 review
|
||||
|
||||
Date: 2026-10-19
|
||||
|
||||
Hop bound: 2 (`HOP_BOUND` in `ui/lib/graph.ts`). Requests above 2 are clamped to that bound.
|
||||
|
||||
Synthetic fixture: `ui/fixtures/large-graph.json`, a chain of 9 nodes (`n0`–`n8`, 8 edges) plus the isolated node `solo`. From `n0` at the hop bound, the neighborhood is `n0`, `n1`, and `n2`. `n8` stays outside. `excludedCount` is 6, matching the relations left out. Focusing `solo` keeps that node in the model and excludes all 8 edges. The same functions cover a cycle, two predicates between one pair, and a node with two parents (`ui/lib/graph.test.ts`).
|
||||
|
||||
R6: no deviation. Large-graph handling is the hop bound. Nodes and relations past it are counted as excluded. They are not drawn, and they are not dropped without that count.
|
||||
|
||||
T01–T08 are done. The test log is `npm test` in `ui/` (32 tests, two runs, both exit 0), saved as `/tmp/grok-goal-aedf5fe6975e/implementer/ui-test-1.txt` and `ui-test-2.txt`. The in-repo proof is `ui/lib/graph.test.ts`, `ui/components/EntityDetail.test.tsx`, and `ui/components/GraphExplorer.history.test.tsx`. Fixture validation and the dev-server bodies are recorded in `workplans/evidence/CONTENT-WP-0004-ImplementationNotes.md`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue