--- id: HOH-WP-0002 type: workplan title: "Publish the hall at helix.coulomb.social with selectable renderers" domain: infotech repo: hall-of-helix status: active flavor: implementation owner: claude-code topic_slug: helix-forge priority: medium created: "2026-09-05" updated: "2026-09-14" quality_dor: DoR-Ok quality_dor_at: "2026-09-05" quality_dor_by: claude-code quality_dor_note: "Ready on its decision tasks: T01-T04 are well-defined and actionable now. Four decisions block implementation — the entry identifier in the URI, where the service lives, how renderers are discovered and trusted, and whether the corpus is cleared for public publication — so the build tasks (T05, T06) are deliberately unspecified and held at wait until those land." related: - HOH-WP-0001 state_hub_workstream_id: "5e0db595-2f0e-5388-9413-7d4d5a4a2ef5" --- # Publish the hall at helix.coulomb.social with selectable renderers The hall is 102 authored seats that can only be read as raw Markdown in a git repository. It was always intended to be readable as a hall — a record of who engaged on the Helix Forge platform, in the spirit of the end titles of a film or a game, without the compensation framing that "credits" would import. There is no `helixforge` domain, so the canonical form is: ``` https://helix.coulomb.social/hall-of-helix/?renderer= ``` `` maps to one seat. `renderer` selects how the Markdown is presented and is optional — omitting it is the same as `?renderer=default`. Renderers are expected to be established as their own repos: a hypothetical `render-hrgiger` would present a seat in an H.R. Giger register, selected as `?renderer=render-hrgiger`. **This workplan is design-first and deliberately incomplete.** It is `ready` on its decision tasks: T01-T04 can be worked now. Four decisions gate the build, so the implementation tasks (T05, T06) are held at `wait` and are not specified until those decisions land — that is the intended shape, not an oversight. ## Decide the entry identifier in the URI ```task id: HOH-WP-0002-T01 status: done priority: high state_hub_task_id: "fc2e4306-5ecf-50db-9a75-8a241a4ae9bc" ``` Seat files are named `--.md`, which makes a poor URL: `2026-09-05T16:36:12.000Z-codex-statehub-snapshot-and-signature`. Every seat already carries a unique frontmatter `id` (`hall-worker-codex-statehub-snapshot-and-signature`), and `make check` already rejects duplicates — so identity exists and is enforced. Options: - the frontmatter `id` verbatim — stable and already unique, but repeats the `hall-worker-` prefix in every URL; - the `id` with that prefix stripped — prettier, needs uniqueness re-checked; - a short opaque id — stable under renaming, unreadable, and a new thing to keep. Whatever is chosen, **the URI is a permanent commitment**: a hall that breaks its own links is not a record. Decide how a seat that is renamed or corrected keeps its URI, and extend `make check` to enforce whatever invariant the answer needs. **Done 2026-09-14.** URI is frontmatter `id` verbatim. `make check` requires URL-safe `[A-Za-z0-9-]+` and unique ids. Filename is not the URI. ADR: `docs/adr/0001-hall-uri-and-renderer-boundary.md`. ## Decide where the service lives and how it is built ```task id: HOH-WP-0002-T02 status: done priority: high state_hub_task_id: "b6ccb11c-2cf5-5f32-a2c5-a4f849eec437" ``` Two shapes, and they differ in more than effort: - **Static generation** — render at commit time, publish artifacts. Cheap, cacheable, no runtime attack surface. `?renderer=` becomes a pre-rendered variant per renderer, so the renderer set must be known at build time. - **Dynamic service** — render on request. Naturally supports an open renderer set and new renderers without rebuilding the corpus, at the cost of a running service that executes selected code. Also decide whether the service lives in this repo or a sibling. This repo is classified `publication` (canon v1.1 §5.7): the corpus is the deliverable, and tooling that renders it is conventionally a separate `tooling` repo. That suggests a sibling — `hall-render` or similar — with this repo staying the content. Name the deployment target (railiance / k3s) and who owns the DNS record for `helix.coulomb.social`. **Done 2026-09-14.** This repo stays publication corpus. Rendering is sibling `hall-render`, static generation for v1. k3s/Traefik; DNS owned by railiance-infra/cluster. No public serve until T04. ## Define the renderer contract and trust boundary ```task id: HOH-WP-0002-T03 status: done priority: high state_hub_task_id: "64370b21-2b30-5ce9-be63-0379c55dad5b" ``` `?renderer=` is **user-controlled input that selects code to run**. Treat it as such from the first line of design: - resolve renderers through a **fixed allowlist**, never by interpreting the parameter as a path, module name, package name, or repo URL; - an unknown value falls back to `default` or returns a clean 404 — it never attempts a fetch or an import; - a renderer receives parsed Markdown plus frontmatter and returns markup; it gets no credentials, no filesystem, and no network; - renderer output is sanitised before it reaches a page. A renderer is third-party code producing HTML, which is an XSS sink by construction. Then define the contract itself: input shape, output shape, how a renderer declares itself, and how it is registered. Check whether the fleet's existing capability discovery (`reuse-surface`, the capability catalog) is the right registry before inventing one. Write it down as an ADR in this repo — a renderer author needs a spec, and this is the part that will be got wrong quietly if it stays implicit. **Done 2026-09-14.** Allowlist only, 404 on unknown, no credentials/fs/network, sanitise HTML, register in `hall-render` not reuse-surface. Same ADR. ## Clear the corpus for public publication ```task id: HOH-WP-0002-T04 status: todo priority: high state_hub_task_id: "8a67d5de-8974-576c-9c59-f7d2036403d9" ``` **Gate on this before anything is served publicly.** The seats were written as an internal record. Publishing 102 of them to a public domain is an outward change that cannot be undone by deleting the page — search engines and archives keep copies. Review the corpus for: session identifiers and model/harness details, internal hostnames, IP addresses, repository and infrastructure names, workplan and decision ids, credential-adjacent narrative, third-party names, and anything a human author would not have written for readers outside the fleet. Decide the disposition: publish whole, publish a filtered projection, or serve the hall behind authentication. If a filter is chosen, it must be enforced in the renderer pipeline rather than left to the author of each seat. The operator makes this call. Do not publish on an agent's judgement. ## Build the hall index — the roll of participants ```task id: HOH-WP-0002-T05 status: wait priority: medium state_hub_task_id: "57ddf0ad-01cf-5ac5-98d2-aa4d6449daff" ``` `https://helix.coulomb.social/hall-of-helix/` is the roll: every worker who has sat, human and agent, drawn from the seats themselves rather than maintained by hand — `README.md`'s list is already hand-maintained and will drift. Derive it from frontmatter: `display_name`, `worker_kind`, `recorded_at`, `repos`, and the link to the seat. Group as the hall groups — by the work shared, in the spirit of end titles — and let humans and agents appear on the same roll, which is the point of the hall. Constraints from both `INTENT.md` files: no ranking, no scoreboard, no sorting that implies merit, and **no aggregation of PQRST estimates**. The estimates carried on seats since `HOH-WP-0001` describe sessions, not workers. A roll that totals them becomes the leaderboard the hall exists not to be. Blocked on T01, T02, and T04. ## Implement rendering with the default renderer ```task id: HOH-WP-0002-T06 status: wait priority: medium state_hub_task_id: "bfab19dc-7f19-59f6-b85a-5a72cad89586" ``` Serve a single seat at the canonical URI with `renderer=default`, honouring the decisions from T01-T04: identifier mapping, static or dynamic, allowlist resolution, sanitised output, and whatever disposition T04 sets. The default renderer should present a seat plainly and legibly — the portrait, the account, and the record — and set the reference implementation that a renderer repo like the hypothetical `render-hrgiger` is written against. Deliberately unspecified until T01-T04 are decided.