commit 35bcfc33ae93a6c109869f786980a5cfa1d4c51c Author: Bendik Aagaard Lynghaug Date: Sun Aug 23 13:06:10 2026 +0200 What shapes us? - redoal.com content: gesture hero, pseudo edition, releases 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 diff --git a/.gitea/workflows/lint-and-reload.yml b/.gitea/workflows/lint-and-reload.yml new file mode 100644 index 0000000..07f03fc --- /dev/null +++ b/.gitea/workflows/lint-and-reload.yml @@ -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" diff --git a/README.md b/README.md new file mode 100644 index 0000000..44181f6 --- /dev/null +++ b/README.md @@ -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 /questions`) diff --git a/aggregates.yaml b/aggregates.yaml new file mode 100644 index 0000000..dd3be86 --- /dev/null +++ b/aggregates.yaml @@ -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] diff --git a/questions/index.yaml b/questions/index.yaml new file mode 100644 index 0000000..6ad5b3a --- /dev/null +++ b/questions/index.yaml @@ -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 diff --git a/questions/shape.yaml b/questions/shape.yaml new file mode 100644 index 0000000..a98bd25 --- /dev/null +++ b/questions/shape.yaml @@ -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] diff --git a/questions/subscribed.yaml b/questions/subscribed.yaml new file mode 100644 index 0000000..7fccb3e --- /dev/null +++ b/questions/subscribed.yaml @@ -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 diff --git a/site.yaml b/site.yaml new file mode 100644 index 0000000..c8e28c1 --- /dev/null +++ b/site.yaml @@ -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 diff --git a/wordmark.svg b/wordmark.svg new file mode 100644 index 0000000..3f025ca --- /dev/null +++ b/wordmark.svg @@ -0,0 +1,12 @@ + + + + + + + + +