--- id: IB-WP-0022 type: workplan title: "Bind infospaces to content-explorer as the presentation UI" domain: communication repo: infospace-bench status: finished owner: grok topic_slug: content-explorer-presentation created: "2026-10-14" updated: "2026-10-14" state_hub_workstream_id: "8b7261bb-9264-515c-948f-b6384e74fdfd" --- # IB-WP-0022 — Bind infospaces to content-explorer as the presentation UI ## Goal Bind concrete infospaces to content-explorer as the presentation UI. Infospace-bench stays the source of the knowledge artifacts. Content-explorer only presents them. The binding is a projection into content-explorer’s existing snapshot contract (`contracts/snapshot.schema.json`, schema version 0.1) and one dataspace presentation manifest (`contracts/manifest.schema.json`, schema version 0.1). Kind labels, facets, and relation wording live in that manifest, so presentation does not require new UI code, an OnCo clone, or a new knowledge store in this repo. `lefevre-reminiscences-of-a-stock-operator` is the worked example. The projection shape is reusable for later infospaces. Lefevre is the example, not a one-off screen. ## Context Read-only shapes this plan cites (do not edit them in this workplan): - Infospace: `infospaces/lefevre-reminiscences-of-a-stock-operator/` (`infospace.yaml`, `artifacts/index.yaml`, `artifacts/sources/`, `artifacts/entities/`, `artifacts/relations/`). - Content-explorer: `contracts/SNAPSHOT.md`, `contracts/snapshot.schema.json`, `contracts/manifest.schema.json`, `architecture/ConnectorContract.md`, `examples/dataspaces/*/manifest.json`, and `content_explorer/contract.py` (`size_errors`, default minimum three kinds and eight entities, enforced for published examples by `scripts/validate_fixtures.py` with `require_size=True`). As of 2026-10-14 the Lefevre tree is a file-backed infospace, not a content-explorer snapshot. `artifacts/index.yaml` records four storage kinds: `source` (6 chapter chunks), `entity` (14 files), `relation` (6 files), and `generated` (summaries, entity bundles, evaluations). Storage kind is not a presentation kind. Sources already carry provenance and rights. Each source entry has `provenance.digest`, `provenance.original_path`, `provenance.imported_at`, and `provenance.book_metadata` with `rights: Public domain in the USA.`, `identifier: http://www.gutenberg.org/60979`, and `source_url: https://www.gutenberg.org/files/60979/60979-h/60979-h.htm`. Entities and relations point back with `generated_from` (and entities also `split_from`). Rights are on the source book metadata, not copied onto each entity file. Entity bodies are Markdown with `## Definition` and `## Category`. The 14 entities use these category values: `instrument` (4), `strategy` (3), `market` (2), and one each of `event`, `evidence_bearing_claim`, `institution`, `error`, and `trader`. That is eight category values and fourteen entities, which can satisfy the published-example minimum only after they are mapped to snapshot `kinds` / `entities`. The trading literature entity contract’s closed list does not include `event`; the projection must map the categories actually stored, not rewrite the files to match the contract. Relation files hold 27 blocks (split on `---`), not one relation per file. `## Relation Type` is the stable vocabulary: `actor_venue` (8), `cause_effect` (7), `strategy_outcome` (5), `risk_mitigation` (4), `lesson_evidence` (3). `## Predicate` is free text (`operates in`, `is`, `was sold at`, and similar) and does not match the snapshot predicate pattern `^[a-z0-9-]+$`. Many subjects and objects are phrases that do not match an entity title. The connector contract forbids a fuzzy join. A snapshot 0.1 document requires `schemaVersion` `0.1`, `dataspace` (`id`, `title`, `description`), `kinds` (`id`, `label`, `plural`), `entities` (`id` as `urn:ce:::`, `kindId`, `title`, `tldr`, `summary`, `sourceRefs`), `relations` (`id`, `predicate`, `from`, `to`, `sourceRefs` with at least one entry), `sources` (`id`, `uri`, `title`, `license`), and `claims`. A manifest 0.1 document requires `schemaVersion` `0.1`, `id`, `home.heading`, `home.featuredKinds`, `navigation`, `kindViews` (`columns`, `facets`), `panels`, `relationLabels` (`forward`, `inverse`), and `factPolicy`. ## Reusable projection One infospace projects to one snapshot plus one presentation manifest. Dataspace id is the infospace slug when it matches `^[a-z0-9-]+$`. Lefevre’s slug already does. | Infospace artifact | Snapshot / manifest field | | --- | --- | | Work-level `book_metadata` (or the equivalent rights-bearing source record on a later infospace) | One `sources[]` row: `uri` from `source_url` or `identifier`, `title` from the book title, `license` from `rights`, `retrievedAt` from the `imported_at` date. Chunk `digest`, `original_path`, and `chunk_id` stay as provenance on that source or in entity properties. Do not drop rights. | | Each `kind: source` chunk | Evidence locator cited by `sourceRefs`. Not a presentation kind by itself. | | Each `kind: entity` file | One `entities[]` row. `kindId` is the `## Category` value with underscores replaced by hyphens so it matches `^[a-z0-9-]+$` (`evidence_bearing_claim` → `evidence-bearing-claim`). `id` is `urn:ce:::`. `title` from the heading. `tldr` and `summary` from `## Definition`. `sourceRefs` from `generated_from` targets, resolved to the work-level source id. Copy provenance (`workflow_id`, `stage_id`, `input_artifact_id`, provider) into `properties`. | | Distinct mapped `kindId` values | `kinds[]` plus manifest `kindViews` (columns and facets) and `home.featuredKinds` / `navigation`. Labels and plural wording are manifest-driven. | | Each relation block | One `relations[]` row when both ends resolve to projected entity ids. `predicate` is `## Relation Type` with underscores replaced by hyphens (`actor_venue` → `actor-venue`). Free-text `## Predicate` is wording or a property, not the predicate id. `sourceRefs` cites the relation artifact’s `generated_from` source. Manifest `relationLabels` supplies `forward` and `inverse` for each predicate. | | Unresolved subject or object | Quarantine. No fuzzy match to entity titles. A second pass may link only an explicit normalized title already stored on an entity. | | `kind: generated` summaries, bundles, and evaluations | Out of the browse set for this binding unless a later task maps them on purpose. They are not required for the Lefevre example. | The same table is the rule for a later infospace. A later infospace supplies its own slug, source rights record, entity categories, and relation types. It does not get a new screen. ## Publication constraint A later published example must satisfy content-explorer snapshot and manifest rules: schema version 0.1, manifest-driven kinds, and the published-example minimum of at least three kinds and eight entities. That minimum is met by mapping this infospace (category → kind, entity file → entity, relation block → relation). The current Lefevre files are not already a snapshot. Do not point content-explorer at `artifacts/` and call it published. Validation of the Lefevre pair uses the existing content-explorer checks (schema, dangling references, duplicate ids, missing sources, license on every source, and `size_errors` / `require_size`). Running those checks does not change the content-explorer application. Tasks in this workplan do not edit `/home/worsch/content-explorer`. ## Non-goals - This workplan does not implement the binding. It does not add the projection, connector, export command, snapshot, or manifest. - This workplan does not rewrite the Lefevre infospace, regenerate it, or change its artifacts. - This workplan does not make content-explorer the system of record. Infospace-bench remains the source of the knowledge artifacts. Content-explorer only presents them. - This workplan does not include building content-explorer UI. Tasks owned here do not change the content-explorer application, its UI, its schemas, or its examples. - No OnCo clone and no new knowledge store in this repo. - No binding of any infospace other than by specifying this reusable shape and carrying it out on the Lefevre example. ## Outcome `infospace_bench.presentation.project_infospace` projects an infospace to one snapshot and one manifest. The Lefevre result is `infospaces/lefevre-reminiscences-of-a-stock-operator/exports/content-explorer/`. `PROJECTION.md` there records the reusable rule. Lefevre artifact files and the content-explorer application were not edited. ## Tasks ### T01 — Specify the reusable projection rule ```task id: IB-WP-0022-T01 status: done priority: high state_hub_task_id: "128d6123-f855-529a-bf8f-7eb7442872cd" ``` Write the projection rule the implementer will code: infospace sources, entities, and relations, including provenance and rights already stored on those artifacts, become one content-explorer snapshot (schema version 0.1) plus one presentation manifest (schema version 0.1). Record the kind mapping (`## Category` → `kindId`), the predicate mapping (`## Relation Type` → `predicate`), the `urn:ce:::` id shape, the work-level source/license row, and the quarantine rule for unresolved relation ends. State that the same shape applies to a later infospace and that Lefevre is the example. Do not treat storage kinds `source`, `entity`, `relation`, and `generated` as presentation kinds. ### T02 — Project the Lefevre snapshot ```task id: IB-WP-0022-T02 status: done priority: high state_hub_task_id: "5861057c-865c-5c4c-8537-9b9a93bda503" ``` Project `infospaces/lefevre-reminiscences-of-a-stock-operator/` into one snapshot. Include the six source chunks’ provenance and the Gutenberg rights (`Public domain in the USA.`) on `sources[].license`. Include the 14 entities with category-derived kinds, definitions as `tldr`/`summary`, and `sourceRefs`. Include relation blocks whose ends resolve, using relation-type predicates. Leave generated summaries and evaluations out of the browse set. Do not rewrite the infospace. ### T03 — Write the Lefevre presentation manifest ```task id: IB-WP-0022-T03 status: done priority: high state_hub_task_id: "922bddc1-ae21-523d-ad60-de1e4536954e" ``` Write one manifest for dataspace `lefevre-reminiscences-of-a-stock-operator` with schema version 0.1. It carries kind labels and plurals’ presentation (`kindViews` columns and facets, `home.featuredKinds`, `navigation`), `relationLabels` forward and inverse wording for each projected predicate, `panels` drawn from `summary`, `relations`, `evidence`, and `claims`, and a `factPolicy`. Presentation uses this manifest. It does not add UI code. ### T04 — Validate the Lefevre pair against the publication rules ```task id: IB-WP-0022-T04 status: done priority: high state_hub_task_id: "f85eae30-b72c-5297-b9cf-d4376b13faa2" ``` Validate the projected snapshot and manifest against schema version 0.1 and the published-example minimum of at least three kinds and eight entities. Check dangling references, duplicate ids, missing sources, and a license on every source. Pass by mapping this infospace. Fail the check if someone treats the current `artifacts/` tree as an already-valid snapshot. ### T05 — Record the reusable rule beside the example ```task id: IB-WP-0022-T05 status: done priority: medium state_hub_task_id: "3852fcf3-d565-592d-8f18-6793948d7473" ``` Record the projection rule next to the Lefevre example so a later infospace reuses the same snapshot and manifest shape. The note names Lefevre as the worked example and states that content-explorer only presents artifacts that infospace-bench still owns.