Level-Aware About — The /about Surface Branches on Level Kind and Projects the Level's Own Graph

Accepted

ontoref
ADR-057 made the SITE a projection of the positioning graph: three doors,

Context

ADR-057 made the SITE a projection of the positioning graph: three doors, projected from spine.ncl, hook-static / prize-live, route-to-live-graph. That ADR is scoped to the difusión vestibule — the doors and their value-props.

The /about route was untouched by it. It rendered a single texts-driven template (about.j2): a personal CV (the jpl level). But the About surface is where a level presents WHAT IT IS, and that differs by the kind of level: a personal ontology (jpl) presents a CV and links; a project (ontoref) should present its own identity — history, defs (axioms/tensions/practices), graph, ADRs, and the catalog of verifiables. The same complaint that opened ADR-057 ("the site content does not correspond to the project") applies to /about: it showed a person where a project should show itself.

Three facts shaped the decision. (1) The data already exists and is queryable daemon-free: defs from core.ncl, the ADR set, the catalog of operations + validators. (2) The htmx site renders /about through a Tera template, NOT the Leptos UnifiedAboutPage — so making /about level-aware is a Tera handler + template change, not a component rewrite. (3) The site already has a hot-reload pattern for request-time graph data: content_graph.json is read by an mtime-cached loader, so a regenerated artifact takes effect with no restart. The About can consume the same way, which keeps the projection current without coupling the page to a live daemon.

Decision

The /about route is level-aware: it branches on the level's kind and, for a project, projects the level's own .ontoref/ graph. This EXTENDS ADR-057's reveal principle (hook-static / prize-live, projection-not-authoring, route-to-live-graph) to a second surface; it does not restate it. What is new here:

A projection contract per level — .ontoref/positioning/about.ncl, typed by about-schema.ncl, with a discriminant `kind = 'Personal | 'Project` and a coherence predicate (kind ⇒ the matching block present, the other absent). The contract declares SELECTIONS, not data: which axioms/tensions/practices to surface, which ADR statuses to digest, which catalog kinds — the data itself is queried from core.ncl / the ADR set / the catalog at projection time. Sparse .ontoref/ yields a partial About, never an error.

One view-model, two consumers — a single daemon-free projector (gen-about-pages) assembles a view-model from about.ncl + .ontoref/. `--out` renders a standalone static page (the marketing/web surface); `--emit-json` writes about.json, the SSR consumption artifact.

Hot-reload view-model, not a baked page — the /about handler reads about.json on an mtime check (mirroring content_graph.json). When the artifact declares kind == "project" the handler renders about_project.j2 with the view-model; otherwise (absent, malformed, or kind == "personal") it falls back to the existing texts-driven about.j2. Regenerating about.json updates live /about with no restart; only handler-LOGIC changes need a rebuild. Data changes never do.

Personal stays as it was — the personal level's About is unchanged: the same texts-driven about.j2. Level-awareness is additive; it does not touch the surface that already worked.

The live graph remains the only daemon-dependent element of the project About — the reveal prize, per ADR-057. Everything else renders from the build-time projection, daemon-free.

Constraints

  • Hard The /about route MUST branch on the level kind: a project level renders the projected project About; a personal level (or absent/malformed projection) MUST fall back to the existing texts-driven personal template. The personal surface MUST stay the default and untouched.
  • Hard The project About MUST be projected from .ontoref/positioning/about.ncl, which declares SELECTIONS (which defs/ADR-statuses/catalog-kinds), never inlined identity data. The data MUST be queried from core.ncl / the ADR set / the catalog at projection time so a source change regenerates the About.
  • Soft The SSR /about MUST consume the projection as a hot-reload view-model artifact (about.json) read at request time on an mtime check, NOT baked into the binary. Regenerating the artifact MUST refresh /about with no restart; only handler-logic changes may require a rebuild.

Alternatives considered

  • Keep /about personal; put the project About at a separate route (a content-kind page)rejected: This is the cheaper Option A and remains valid as the standalone static web surface. Rejected as the CANONICAL answer because /about itself would not become level-aware — a visitor to a project site's real /about would still get a person. Level-awareness of the canonical route is the point.
  • Project the About live from the daemon at request time (a daemon HTTP client in the handler)rejected: Couples /about to a running daemon, breaking the hook-static/prize-live split (ADR-057) and local-fallback (ADR-029): the page goes dark when the daemon is down. The hot-reload artifact gives most of the currency benefit while keeping the page daemon-free; the live graph stays the only daemon element.
  • Rewrite /about as the Leptos UnifiedAboutPage with the projection embeddedrejected: The htmx site renders /about through Tera, not the Leptos component. A Leptos rewrite is a far larger blast radius for no benefit over a Tera handler + template that reads the view-model.
  • Bake the project About into the binary at build (no runtime artifact)rejected: Every .ontoref/ change would then require a binary rebuild + redeploy to refresh identity. The mtime-cached artifact (content_graph.json pattern) decouples data refresh from binary builds — regenerate about.json, no restart.

Anti-patterns

  • Showing a Person Where the Project Should Show Itself — A project level's /about renders a generic CV / personal template instead of projecting the project's own history, defs, graph, ADRs, and catalog. The About does not correspond to the level — the same gap ADR-057 closed for the doors.
  • Hand-Authoring the Project About — The project About is written as site content (defs, ADR list, history) rather than projected from about.ncl + queried from .ontoref/. The copy drifts from the ontology it claims to present.
  • Baking the About Into the Binary or Gating It on the Daemon — Either the project About is compiled into the server (so every .ontoref/ change needs a rebuild) or it is fetched live from the daemon at request time (so the page goes dark when the daemon is down). Both break the hot-reload / local-fallback discipline.

Related ADRs

ADR-057 · ADR-035 · ADR-045 · ADR-029 · ADR-043

Was this useful? Rate it
Got something to add? Tell me what you think, what you'd suggest, or whether we should keep exploring this topic.
· reads

We use cookies to help this site function, understand service usage, and support marketing efforts. Cookie Policy for more info.