The lint moved into uhhm/portal as portal lint
Test / test (push) Successful in 1m15s

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GT37Z1Xtfd9pUuQtMTg6Yt
This commit is contained in:
Bendik Aagaard Lynghaug
2026-09-30 15:33:54 +02:00
co-authored by Claude Fable 5.1
parent e3c68f9441
commit 74c9dc015c
+8 -55
View File
@@ -1,57 +1,10 @@
# iris
# iris, now `portal lint`
The iris over a [portal](https://project.uhhm.no/uhhm/portal) site. A
content push is an incoming wormhole; nothing comes through until it
checks out.
The lint lives in [uhhm/portal](https://project.uhhm.no/uhhm/portal)
since portal 0.6, as the `portal lint` command of the same binary that
runs a site; its documentation is
[The lint](https://portal.uhhm.no/lint.html). A content repo's CI
downloads the release's `portal` and runs `portal lint --path questions`.
```
iris check --path questions # a local checkout
iris check --repo https://project.uhhm.no/uhhm/questions
iris --path questions # the same, for one-line CI
```
`check` loads a content repo exactly the way the running site does,
validates it (every action lands on a page, every transition is one
the state machine allows, every recorded bucket is read back
somewhere), and then holds it to the business needs the repo declares
in `needs.yaml`, when it has one:
- a path of submissions gets each kind of visitor's answer into the
bucket it names, within a submission and required-field budget;
- the handling group holds a desk over that bucket, and every
finished state is reachable through the buttons it (and any
`also_moved_by` group) offers; no record strands on the way;
- every stage the business named is a state of the machine.
A need marked `planned` warns instead of failing. Exit status is the
verdict, so a content repo's CI is one line.
Beyond the verdict, `check` exports what a trainer needs to grade the
wording: `--needs-tasks` writes the personas as typed choice tasks
(`--skim` for headings only), `--needs-score` grades an engine's
answers, and `--needs-sim` writes a resolved model of the whole site.
`iris replay` runs simulated cases through the site's real aggregate
engine on a throwaway JetStream and reports every bucket by state;
`--report-only` takes the same scorecard from a live site's buckets.
See [portal-trainer](https://project.uhhm.no/uhhm/portal-trainer) for
what sits around those.
## Matching the site
Every type iris reads is portal's own: portal is a library dependency
pinned to a release tag in `Cargo.toml`, and iris carries the same
version number as that tag, so `iris v0.3.39` is the lint for portal
v0.3.39 and nothing else. A content repo pins `IRIS_RELEASE` to the
`PORTAL_RELEASE` its site runs. Portal's own release tarball ships the
matching `iris` binary too, at `/srv/app/<instance>/current/iris`.
## Release
Iris is released by portal's publish job, never by hand: when a
portal tag is pushed, that job re-pins this crate to the tag, sets
the version to match, builds and tests it, adds the changelog line,
and pushes the commit and the tag here. This repo's own CI then
attaches the binary to the Gitea release as `iris`. A portal change
to something the lint reads fails the portal release at that step.
Changes to iris itself land on `main` between releases and ship with
the next portal tag.
The `iris` releases up to v0.5.11 stay here and keep working for the
`IRIS_RELEASE` pins that name them; nothing new is published.