content-explorer/content_explorer/render.py
tegwick 072a7fa550 Freeze the v0.1 contract and the local ingest connector.
The snapshot and manifest schemas, both example dataspaces, and the shared text renderer now pass the fixture validator and the negative contract tests. JSON, NDJSON, and Markdown frontmatter publish a snapshot only when rights, identity, and references allow it. CONTENT-WP-0001 and CONTENT-WP-0003 are marked finished against those artifacts. CONTENT-WP-0000-T04 stays open. SCOPE.md and the 19:05 scope-against-intent note record the stop.

Assistant: grok
Assistant-Session: 01a130f1-abfb-7d71-9cd6-a8b75ec7f95a
2026-10-12 19:07:32 +02:00

60 lines
2.5 KiB
Python

"""Render a snapshot with whatever labels the manifest supplies.
The text below is the shared explorer. It must not name a dataspace, a kind,
or a predicate. Those strings come from the snapshot and the manifest.
"""
from __future__ import annotations
from content_explorer.contract import resolve_claims
def render_explorer(snapshot: dict, manifest: dict) -> str:
kinds = {kind["id"]: kind for kind in snapshot.get("kinds", [])}
entities = {entity["id"]: entity for entity in snapshot.get("entities", [])}
claims = snapshot.get("claims", [])
policy = manifest.get("factPolicy", "show-all")
lines: list[str] = [manifest["home"]["heading"], ""]
for section in manifest.get("navigation", []):
names = [kinds[kind_id]["plural"] for kind_id in section["kinds"] if kind_id in kinds]
lines.append(f"{section['label']}: {', '.join(names)}")
lines.append("")
for kind_id in manifest["home"]["featuredKinds"]:
kind = kinds.get(kind_id)
if kind is None:
continue
lines.append(f"## {kind['plural']}")
members = [entity for entity in snapshot.get("entities", []) if entity.get("kindId") == kind_id]
if not members:
lines.append("(none)")
for entity in members:
field = resolve_claims(
[claim for claim in claims if claim.get("subjectId") == entity["id"]],
"tldr",
policy,
)
if field["state"] == "unknown":
shown = "unknown"
elif field["state"] == "contradicted":
shown = "contested: " + " | ".join(str(value) for value in field["values"])
elif field["state"] == "withheld":
shown = "withheld"
elif field["values"]:
shown = str(field["values"][0])
else:
shown = entity.get("tldr", "")
lines.append(f"- {entity['title']}: {shown}")
lines.append("")
lines.append("## Relations")
labels = manifest.get("relationLabels") or {}
for relation in snapshot.get("relations", []):
predicate = relation["predicate"]
wording = labels.get(predicate, {}).get("forward", predicate)
origin = entities.get(relation["from"], {}).get("title", relation["from"])
destination = entities.get(relation["to"], {}).get("title", relation["to"])
lines.append(f"- {origin} — {wording} → {destination}")
lines.append("")
return "\n".join(lines).rstrip() + "\n"