What shapes us? - redoal.com content: gesture hero, pseudo edition, releases
Lint and reload / lint (push) Successful in 3s
Lint and reload / reload (push) Failing after 0s

The 2024 lysbue question returns as live content: a gesture-drawing
hero and form (type: gesture, wired to wss://relay.redoal.com),
redoal/redoal's releases via the gitea_releases source (unlinked
while the repo is private), and a subscribe flow. site.yaml rebrands
the portal instance; buckets are redoal_-prefixed to coexist with
uhhm's on the shared JetStream.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Bendik Aagaard Lynghaug
2026-08-23 13:06:10 +02:00
co-authored by Claude Fable 5
commit 35bcfc33ae
8 changed files with 240 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
name: Lint and reload
# Lint runs on PRs too - it's the status check branch protection
# requires before the development-commit automation's PRs may merge
# (merge_when_checks_succeed). The reload only ever fires on a push
# that actually landed on main.
on:
push:
branches: [main]
pull_request:
jobs:
lint:
runs-on: bare
steps:
- uses: actions/checkout@v4
# Same bare-metal runner/host as portal's own deploy job, which
# publishes this binary to a stable path on every deploy - runs
# portal's real transition-table/shape validation directly, not a
# hand-maintained yq/jq subset of the same rules (lint.sh, now
# superseded and removed).
- name: Lint questions
run: /srv/app/uhhm-portal/current/question_lint --path questions
reload:
runs-on: bare
needs: lint
if: github.event_name == 'push'
steps:
# Tells every running portal instance to re-fetch and atomically
# swap in the new content - see content::watch_for_reload in the
# portal repo. Fire and forget: no reply expected, no payload
# needed (the subject alone is the whole message).
- name: Tell portal to reload content
run: nats pub portal.content.reload '' --server "nats://infra:${{ secrets.NATS_TOKEN }}@127.0.0.1:4222"
+41
View File
@@ -0,0 +1,41 @@
# questions (redoal.com)
The content behind [redoal.com](https://redoal.com) — a second face of
the same [portal](https://project.uhhm.no/uhhm/portal) question engine
that serves uhhm.no. Every page is a YAML file under `questions/`;
pushing to `main` lints and then tells every running portal instance
to hot-reload.
The full schema reference lives in
[uhhm/questions' README](https://project.uhhm.no/uhhm/questions) —
this repo only notes what's distinctive here:
- **`site.yaml`** rebrands the instance: title `redoal`, its own
wordmark, and a `gesture` hero — the landing page opens on a
drawing canvas wired to `wss://relay.redoal.com` (the
`redoal-relay` crate in [redoal/redoal](https://project.uhhm.no/redoal/redoal)),
so visitors' similar strokes echo to each other live. The wordmark
is white-stroked like uhhm's, because portal's light theme lands
wordmarks as ink via an invert filter.
- **`type: gesture`** on `index.yaml`'s "Our Understanding" — the
pseudo edition of the network: draw a path, it becomes a real
20-byte gesture key (computed by the relay with the canonical Rust
pipeline), and the submitted answer stores `{points, key}` in the
`redoal_gestures` bucket. Marked `optional: true` deliberately:
the widget's hidden input is invisible to HTML required-validation.
- **`gitea_releases`** on "Our Composition" — advertises
redoal/redoal's releases. The jq filter pins `url: null` while that
repo is private (a private release's html_url 404s for anonymous
visitors); flip it to `.html_url` if the repo ever goes public.
- **Bucket names are `redoal_`-prefixed** (`redoal_gestures`,
`redoal_subscribers`): both portal instances share one NATS
JetStream, and bare names would collide with uhhm's buckets.
Lint locally before pushing:
```
/srv/app/uhhm-portal/current/question_lint --path questions
```
(or from a portal checkout:
`cargo run --features ssr --bin question_lint -- --path <this repo>/questions`)
+16
View File
@@ -0,0 +1,16 @@
# State graphs for event-sourced buckets - see portal's
# src/aggregates/mod.rs. Bucket names are redoal_-prefixed because
# both portal instances (uhhm.no and redoal.com) share one NATS
# JetStream; a bare "subscribers" would collide with uhhm's.
#
# redoal_gestures (index.yaml's record_as for drawn paths) has no
# entry on purpose: plain KV, no lifecycle - a drawn gesture is a
# fact, not a process.
aggregates:
- bucket: redoal_subscribers
initial: open
states:
open: { event: subscribed }
unsubscribed: { event: unsubscribed }
transitions:
open: [unsubscribed]
+77
View File
@@ -0,0 +1,77 @@
id: /
name: What shapes us?
description: >
redoal is a gesture-addressed network — peers find each other by
drawing similar shapes. The gesture is the address. Draw one above
and see who's near.
responsible:
name: Bendik Aagaard Lynghaug
contact: bl@uhhm.no
alternatives:
- name: Our Understanding
description: >
By associating similar movements while facilitating discourse we
discover signal within chaos. Draw a path — the network answers
with the shapes it heard nearby.
action: /shape
consequence: [Find what follows]
record_as: redoal_gestures
encouragements:
- What you don't know — your collaborators will.
features:
- name: ""
description: Start by creating a path
requirements:
# optional: the widget's hidden input skips HTML required-
# validation, so required would be unenforceable anyway
# (see the schema notes in this repo's README).
- name: curve
label: Curve
placeholder: Lines
type: gesture
relay: wss://relay.redoal.com
optional: true
- name: email
label: Email, if the echoes should reach you later
type: email
optional: true
- name: Our Composition
description: >
The network as it is being built — every release of the core,
as it lands.
features:
- name: Releases
description: Cut from redoal/redoal on this Gitea.
resource:
source:
kind: gitea_releases
owner: redoal
repo: redoal
public: true
# url pinned to null while the repo is private - a private
# release's html_url 404s for anonymous visitors, and the
# card renders an unlinked heading instead (same lesson as
# uhhm/questions 9b7162f).
jq: >
.[] | {name: .name, description: .body, tag: .tag_name,
published: .published_at, url: null}
- name: Our Devotion
description: >
Notes from the build — sent only when there is something worth
saying.
action: /subscribed
consequence: [Subscribe]
record_as: redoal_subscribers
encouragements:
- Consider yourself posted.
features:
- name: Where to send it
description: ""
requirements:
- name: name
label: Name
- name: email
label: Email
type: email
+26
View File
@@ -0,0 +1,26 @@
id: /shape
route: ^/shape
followup: true
name: The path continues
description: >
Your shape is in the room now. Echoes of it reach whoever draws
nearby — and theirs reach you, whenever you come back to draw again.
alternatives:
- name: What just happened
description: ""
features:
- name: An address, not an upload
description: >
The stroke became a 20-byte gesture key — a compressed
encoding of its shape. Similar shapes land on nearby keys;
that proximity is the whole network.
- name: Nothing to undo
description: >
A drawn path is a fact, not an account. There is no profile
behind it unless you left an email.
- name: Draw another
description: >
The network gets more interesting with every shape it hears.
action: /
consequence: [Back to the canvas]
+23
View File
@@ -0,0 +1,23 @@
id: /subscribed
route: ^/subscribed
followup: true
name: What should you expect?
description: >
Notes when the network learns something — that's the whole promise.
alternatives:
- name: You're on the list
description: ""
features:
- name: Rare, by design
description: A few considered notes a year — nothing more.
- name: Easy to leave
description: Every note carries a genuine, one-click unsubscribe.
- name: Unsubscribe
description: >
Using the link from one of our emails? Confirm below and we'll
stop writing.
self_transition:
bucket: redoal_subscribers
to: unsubscribed
label: Unsubscribe me
+9
View File
@@ -0,0 +1,9 @@
# Instance branding - see the schema notes in this repo's README and
# portal's content loader (src/content.rs, SiteConfig). The relay URL
# here drives the landing hero's ambient echoes; the same URL appears
# on index.yaml's gesture requirement for the form widget.
title: redoal
wordmark: https://project.uhhm.no/redoal/questions/raw/branch/main/wordmark.svg
hero:
kind: gesture
relay: wss://relay.redoal.com
+12
View File
@@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" width="710" height="220" viewBox="-30 -90 710 220" fill="none" stroke="#fff" stroke-width="26" stroke-linecap="round">
<!-- r e d o a l in the same geometric skeleton style as uhhm's
wordmark: 84-wide letters on a 124 grid, x-height 0..100,
ascenders to -60. White strokes so the light theme's
invert filter (style/main.css) lands it as ink on paper. -->
<path d="M0,0 V100 M0,42 A42,42 0 0 1 84,42"></path>
<path d="M124,50 H208 M208,50 A42,42 0 1 0 205.5,64.4"></path>
<path d="M332,-60 V100 M248,50 A42,42 0 1 1 332,50 A42,42 0 1 1 248,50"></path>
<path d="M372,50 A42,42 0 1 1 456,50 A42,42 0 1 1 372,50"></path>
<path d="M580,0 V100 M496,50 A42,42 0 1 1 580,50 A42,42 0 1 1 496,50"></path>
<path d="M620,-60 V100"></path>
</svg>

After

Width:  |  Height:  |  Size: 809 B