From 3179be0d11dde488360bfb9359038eadc4a30ab7 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Sun, 8 Nov 2026 21:09:19 +0100 Subject: [PATCH] =?UTF-8?q?Answer=20prose=20round=201:=200=20=F0=9F=94=B4,?= =?UTF-8?q?=2010=20=F0=9F=9F=A1=20(0=20misread);=20define=20code=20health,?= =?UTF-8?q?=20restore=20the=20topic=20index,=20give=20each=20decision=20a?= =?UTF-8?q?=20premise=20of=20its=20own?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/release.yml | 5 +- AGENTS.md | 23 +++++- docs/decisions.md | 100 +++++++++++++------------ examples/plugins/admin/admin-shared.ts | 3 +- src/auth/gate.ts | 6 +- src/postgres.test.ts | 6 +- src/server.ts | 3 +- views/partials/shell.ejs | 4 +- 8 files changed, 88 insertions(+), 62 deletions(-) diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 070f68d..1ccaf1b 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -69,8 +69,9 @@ jobs: if: always() run: | set -uo pipefail - # Cleanup, and the runner's Docker config is shared (docs/decisions.md) — a lost race here - # must not fail a release that published, nor skip the overview job that follows. + # This is cleanup: it must not fail a release that published, nor skip the overview job + # that follows. The runner's Docker config is shared, so a logout can lose a race + # (docs/decisions.md → "CI docker logins share the runner host's Docker config"). docker logout gitea.larvit.se || true docker logout docker.io || true diff --git a/AGENTS.md b/AGENTS.md index e272525..4128197 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,8 +10,9 @@ change, sweep the prose you touched — this file, `README.md`, the example READ comments — and cut it back to what a competent reader could not infer: - **Delete history.** Git holds it. No "this moved from X", "used to be Y", "was tried and - rejected", "(declined twice)", dated changelog entries, or the symptom that prompted a fix. Record - the decision and the reason it *currently* turns on, nothing else. + rejected", "(declined twice)", dated changelog entries (a decision's date in `docs/decisions.md` + is not one), or the symptom that prompted a fix. Record the decision and the reason it + *currently* turns on, nothing else. - **Delete restatement.** A comment that says what the adjacent line says, a doc paragraph that re-explains a table above it, a file-map entry that expands the filename. The fix is deletion, not trimming. @@ -69,8 +70,10 @@ branch, create a PR and merge it when the CI/CD turns green. ## Decisions -In `docs/decisions.md`, each with its reasoning and the premise it rests on. A review honours them -rather than re-raising them. +Each title below is an entry in `docs/decisions.md`, with its reasoning and the premise it rests +on; a review honours them. + +### Structure & contracts - `src/` is grouped by concern, and the core ships no domain screens - Plugins and config import the host only through the two barrels @@ -88,6 +91,9 @@ rather than re-raising them. - `ctx.chrome` is lazily memoized, never built unconditionally - A plugin-owned render always runs on that plugin's context - Email is delegated to Kratos + +### Authorization + - The vocabulary is `User` → `Group` → `Permission`, and there is no `Role` - A permission name is always `:`, enforced at discovery - Permission names are authored in plugin code; only grants live in Keto @@ -101,6 +107,9 @@ rather than re-raising them. - `users:write` and `groups:write` each amount to full administrative access - The CSRF token is unbound to the session - Plainpages says "user" everywhere, where Ory says "identity" + +### i18n + - The locale lives in the URL, never in a cookie - The core building blocks carry the locale, so a plugin doesn't have to - `locale` and the i18n view locals are reserved by the host @@ -110,9 +119,15 @@ rather than re-raising them. - An unknown translation key renders as itself - `t()` returns raw text, and the view escapes it - RTL is out of scope until there is a real use case + +### UI + - A dropdown is a `