Files
portal/vendor/trainer/runs/uhhm-2026-09-28

uhhm.no, rebuilt for portal 0.5.1 and previewed from a branch

Scrapped 2026-09-28 after the preview: the original reads better. The branch, the instance, its NATS and its Caddy route are removed; the preview.uhhm.no DNS record remains in uhhm/infrastructure. What carried over to the trainer: the 0.5 schema, the mail scoring, and the iris mail checks.

plans/uhhm.yaml (the 2026-09-23 plan) built with round 8's words (runs/uhhm-2026-09-23/words-r8.json), after the builder learned portal 0.5's content schema. Lints green with iris v0.5.1: 15 pages, 9 aggregates, 58 access rules, 7 needs met.

What is new against round 8:

  • A submitter's own moves say where they may be made from. Portal 0.5 reads a self_transition without from as the initial state alone; the builder writes from: for every one. (The Tomter Vel content deployed on 2026-09-23 fails the 0.5 lint for this reason: its "hjelpen er gitt" link moves from formidlet.)
  • The approved changes to this site are public. propose gets watched_by: [public] and public_states: [approved], so /status/development_proposals lists what was approved, without who proposed it (submitted_by is private). The page's words are Sonnet's, told that the list shows only approved changes (words-status.json); the front door's card for it is worded by hand (overrides.json).

Build, reproducibly, without a model:

portal-trainer build --plan plans/uhhm.yaml --out runs/uhhm-2026-09-28/site \
  --words runs/uhhm-2026-09-23/words-r8.json \
  --words runs/uhhm-2026-09-28/words-status.json \
  --words runs/uhhm-2026-09-28/overrides.json --lint iris

The preview

uhhm/questions branch preview/trainer carries this build, and .gitea/workflows/preview.yml serves any preview/* branch as app@uhhm-preview on ergo (:3012, preview.uhhm.no):

  • its own NATS container (uhhm-preview-nats, 127.0.0.1:4232), so a preview never writes into uhhm.no's buckets, and gdo, which reads the real NATS, never delivers its mail;
  • no sign-in, so the owners' and custodians' desks are not reachable in a preview;
  • the pushed commit, not the branch name, as CONTENT_BRANCH: portal puts the ref into Gitea's git/trees/<ref> path, and the slash in preview/trainer 404s there. A portal fix would let a preview follow its branch with the normal reload.

preview.uhhm.no needs a DNS record (uhhm/infrastructure pull request 4, then a manual terraform apply) before Caddy can get it a certificate. Until then the preview answers on the host: curl -H 'X-Forwarded-For: 127.0.0.1' http://127.0.0.1:3012/.

Not in this build: grants, deadlines (after) and type: record. Nothing in the uhhm plan is an approval that means membership of a group that exists, nor a stage a clock should end, and type: record needs dynamic pages the builder does not make yet.

The mails, scored as a person reads them

rate --repo now rates every mail the site sends, the invite mail included (site.yaml mail.invite, written by the builder whenever a plan onboards people and has a sender). Besides LIX, each mail is put to its reader - someone who sent a form, or someone just brought in - with three questions: what happened and to what, what can I do now, who wrote and how do I answer. Each is also put to a gutted twin ("News. There is news."); a yes the twin also gets fails the control. The mail is read as it arrives, placeholders filled with plausible values.

Round Mails All three answered iris mail warnings
1 (rate-round1.txt) round 8's, plus the invite 7 of 11 0
2 (not rated) reworded: name the case and the sender - 5
3 (rate.txt) reworded again with every rule below 11 of 11 0

Round 1's four misses never named their case ("We'd like to take this on", "your message", "your draft" for what was a description) or who wrote; the rule became: every mail names the case by a field the person filled in and ends with the business's name. Following it, round 2 found new ways to go wrong, each now a rule too:

  • {project}, a whole brief, in a subject line, and {org_contact}, usually empty, in a greeting (the five warnings): the prompt marks fields (long) and (optional) and keeps both out;
  • "the custodian has written why in the reply", which no desk can do: a decision's mail offers a reply instead, since a reply reaches the people who decided as a note.

The deterministic half of that went into iris (uhhm/iris PR 1): a placeholder nothing fills, a link to a page that does not exist, a grant on a site that mails no one, an invite without {link} fail; a placeholder only some forms collect or all mark optional, a long answer in a subject, a dialogue that never says how it ended, and a mail about a case the person may act on without their link, warn. The preview branch carries round 3's mails.