Gate-Liste widerspricht sich: AGENTS.md § Gates, instructions/gates.md und die Gate-Namen der Kommando-Datensätze #194

Closed
opened 2026-10-06 19:53:46 +00:00 by torben · 4 comments
Owner

Gefunden beim Bau von #188: die generierte docs/reference/exit-codes.md listet die Gates so, wie die Datensätze sie deklarieren, und das ist eine andere Liste als in den Dokumenten, die Gates beschreiben.

Stand

Abgeschlossen. Veröffentlicht in 9.0.0-beta.9 (Commit e9f4759), CI grün: Run 598 und 599. Im Abschluss nachgezogen in 9.0.0-beta.10 (Commit 5915b07): Hilfe- und Ursachentexte von sync und publish schrieben noch „rebase-review gate" statt des Anzeigenamens „Rebase-Review Gate"; CI grün: Run 600 und 601. Die übrigen docs/-Seiten, READMEs und Kontrakte wurden gegen die Änderung gelesen; keine weitere nennt Gates mit Zahl oder vollständiger Liste.

Befund (geprüft gegen 1559f4b, 9.0.0-beta.8)

Quelle Was sie als Gates nennt
AGENTS.md § Gates (Z. 281, „Five limits are enforced in code…") Mass-Update, Publish-Remote, Upload Review, Guideline Push, Iteration Budget / Loop-Breaker (Exit 1, nicht 42). Kein rebase-review.
instructions/gates.md Z. 9 („Two limits are enforced in code…") zwei - gemeint sind wohl die zwei Arten (Exit 42 und Budget), gezählt wird aber „limits"
instructions/gates.md § Exit 42, Z. 37 („Five gates use it today") Mass-Update, rebase-review, Publish-Remote, Upload Review, Guideline Push. Die Frontmatter-description nennt sync nicht.
docs/explanation/why-gates-are-code.md Z. 3 und 37 („five hard limits", „The five gates ask four different kinds of question") dieselben fünf wie AGENTS.md, kein rebase-review
Properties.gates der Datensätze (→ -h, tools/CONTRACT.md, docs/reference/exit-codes.md) mass-update, publish-remote, rebase-review (git_publish.py:1341 sync, :1513 publish), upload-review (upload_cmd.py:165), guideline-push (export_cmd.py:253), **human-intervention-required (\new project` only)** (new_page.py:382`)

Drei Zählungen, drei verschiedene Mengen - Invariante 8 verletzt.

new deklariert ein Pseudo-Gate, weil CommandRecord.__post_init__ (cli_contract.py:157) eine Exit-42-Failure ohne gates verweigert; new project hat eine solche (new_page.py:492, HumanInterventionRequired). Das widerspricht docs/explanation/why-gates-are-code.md § „Exit 42 is a posture, and it outgrew the gates", die HumanInterventionRequired und die Preflight ausdrücklich als Exit 42 ohne Gate einordnet.

Entscheidungen (Betreiber, 2026-10-07 - alle Empfehlungen angenommen)

  1. rebase-review ist ein Gate. Es verweigert eine mögliche Operation, bis ein Mensch die Ausgabe gelesen hat, und wird per Token (--confirm-rebase) freigegeben - die Form des Mass-Update Gate. Anzeigename: Rebase-Review Gate (so auch in gates.md, das heute klein „rebase-review gate" schreibt). Die Erklärseite bekommt unter „Why different mechanisms, not one" einen Absatz zur Frage, die es stellt: kollidiert das Eingehende logisch mit dem, was ich gleich veröffentliche? - Token-Form, weil die Antwort je Rebase eine andere ist.
  2. Der Exit 42 von new project ist kein Gate (Option b), wie die Erklärseite es schon sagt. new_page.py deklariert gates=(). __post_init__ erlaubt eine Exit-42-Failure ohne Gate; die Generik-Zeile in exit_status_entries (Z. 371) bleibt unverändert, sie greift nur bei deklarierten Gates ohne explizite 42-Ursache. new project bleibt in docs/reference/exit-codes.md sichtbar, im Abschnitt „Exit 42 causes" (aus den Failures erzeugt, reference_doc.py ab Z. 233). Verworfen: (a) als Gate aufnehmen, (c) anderer Exit-Code - beide widersprechen der Erklärseite.
  3. Die eine Liste ist AGENTS.md § Gates. Normativ, in jeder Session geladen. § Gates nennt keine Zahl im Fließtext mehr, die schon beim nächsten Gate falsch wäre („Five limits" → eine Formulierung ohne Zahl). instructions/gates.md zählt nicht mehr selbst (Z. 9 und Z. 37 verlinken auf § Gates), behält aber die Prozedur je Gate. Die Erklärseite nennt keine Zahl mehr und verlinkt ebenfalls; ihre Aussage „vier Arten von Fragen" darf bleiben, wenn sie mit dem rebase-review-Absatz noch stimmt (sonst anpassen).
  4. Mechanisch gehalten, minimal:
    • Register GATES in tools/chemenu/cli_contract.py: Datensatz-Name → Anzeigename in § Gates, plus ob das Gate mit 42 endet. Einträge: mass-update → „Mass-Update Gate", publish-remote → „Publish-Remote Gate", rebase-review → „Rebase-Review Gate", upload-review → „Upload Review Gate", guideline-push → „Guideline Push Gate" (alle Exit 42); iteration-budget → „Iteration Budget Gate / Loop-Breaker" (Exit 1, von keinem Datensatz deklariert - es gilt für alle).
    • Properties (bzw. CommandRecord.__post_init__) verweigert einen Gate-Namen, der nicht im Register steht, mit ValueError beim Import - so wie heute schon die Exit-42-Prüfung.
    • Neuer Check in tools/chemenu/commands/docs_verify.py: die fett gesetzten Eintragsnamen der Aufzählung in AGENTS.md § Gates (Muster - **<Name>.**) sind genau die Anzeigenamen des Registers, und jedes Exit-42-Gate des Registers wird von mindestens einem Datensatz deklariert. Neue Failure im docs verify-Datensatz (docs_verify.py:1250) mit Ursache und Reaktion.
    • Verworfen: § Gates aus dem Register generieren (Marker-Block in AGENTS.md) - zieht normative Prosa in Code, für sechs Zeilen zu viel Mechanik.

Betroffene Dateien

  • AGENTS.md § Gates (Zählung raus, Eintrag Rebase-Review Gate.); dazu § File naming, wo die Erklärseite mit „the five gates" beschrieben war
  • instructions/gates.md (Z. 9, Z. 37, Anzeigename, Frontmatter-description um sync ergänzen)
  • docs/explanation/why-gates-are-code.md (Z. 3, Z. 37, Absatz für rebase-review)
  • tools/chemenu/cli_contract.py (Register GATES, Prüfung unbekannter Namen, __post_init__ gelockert)
  • tools/chemenu/commands/new_page.py (Datensatz von new: gates=())
  • tools/chemenu/commands/docs_verify.py (neuer Check + Failure im Datensatz)
  • tools/chemenu/commands/git_publish.py (Anzeigename „Rebase-Review Gate" in Hilfe- und Ursachentexten von sync und publish)
  • Tests: tools/chemenu/tests/test_cli_contract.py (unbekannter Gate-Name verweigert; Exit 42 ohne Gate zulässig), tools/chemenu/tests/test_docs_verify.py (neuer Check: fehlender und überzähliger Eintrag in § Gates, Exit-42-Gate ohne deklarierenden Datensatz); test_reference_doc.py nutzte einen Fixture-Gate-Namen keep, der nun mass-update heißt
  • veraltete Zählungen in Code-Kommentaren (doctor.py, errors.py, git_publish.py, mcp/server.py, test_git_publish.py)
  • danach docs contract --apply und docs reference --apply (regeneriert tools/CONTRACT.md, docs/reference/exit-codes.md, docs/reference/commands/pages.md)
  • Doc-Pull-Through nach instructions/dev/doc-pull-through.md (z. B. docs/reference/-Prosa, README.md, falls dort Gates gezählt werden)

Nicht im Umfang: die kb/-Konzeptseiten (Mass-Update Gate, Publish-Remote Gate - „Drittes … Gate" -, Iteration and Cost Limits, AGENTS.md). Korpus, nachgezogen über die normale Ingest-Strecke.

Version

MINOR (neuer docs verify-Check). Kein Kommando, kein Flag, keine Datei-Form entfällt → in beide Richtungen drop-in. Der laufende Kandidat steht bereits auf 9.0.0 (MAJOR), --minor eskaliert also nichts. Umgesetzt als 9.0.0-beta.9; der Anzeigenamen-Nachzug im Abschluss ist ein --patch (9.0.0-beta.10).

Akzeptanzkriterien

  • Kein Dokument außer AGENTS.md § Gates zählt oder vollständig aufzählt die Gates; AGENTS.md, instructions/gates.md und docs/explanation/why-gates-are-code.md nennen keine Anzahl von Gates oder Limits (rg -in "(two|three|four|five|six) (gates|limits|hard limits)" über diese drei Dateien ist leer; zeilenübergreifend geprüft, rg -U).
  • AGENTS.md § Gates führt das Rebase-Review Gate.
  • Ein Datensatz mit einem Gate-Namen außerhalb des Registers scheitert beim Import mit ValueError (Test).
  • Ein Datensatz mit Exit-42-Failure und ohne gates ist zulässig (Test); new deklariert kein Gate.
  • docs/reference/exit-codes.md führt unter „Gates by command" genau guideline-push, mass-update, publish-remote, rebase-review, upload-review, und new project weiterhin unter „Exit 42 causes".
  • docs verify scheitert, wenn in § Gates ein Registereintrag fehlt, ein Eintrag ohne Registereintrag steht, oder ein Exit-42-Gate von keinem Datensatz deklariert wird (Tests); auf dem Baum ist er grün.
  • tools/CONTRACT.md und docs/reference/ sind regeneriert.
  • pytest (2554 bestanden, 3 übersprungen), docs verify, instructions verify lokal grün; CI grün auf e9f4759 (Run 598 und 599) und auf 5915b07 (Run 600 und 601).
Gefunden beim Bau von #188: die generierte `docs/reference/exit-codes.md` listet die Gates so, wie die Datensätze sie deklarieren, und das ist eine andere Liste als in den Dokumenten, die Gates beschreiben. ## Stand Abgeschlossen. Veröffentlicht in 9.0.0-beta.9 (Commit `e9f4759`), CI grün: Run 598 und 599. Im Abschluss nachgezogen in 9.0.0-beta.10 (Commit `5915b07`): Hilfe- und Ursachentexte von `sync` und `publish` schrieben noch „rebase-review gate" statt des Anzeigenamens „Rebase-Review Gate"; CI grün: Run 600 und 601. Die übrigen `docs/`-Seiten, READMEs und Kontrakte wurden gegen die Änderung gelesen; keine weitere nennt Gates mit Zahl oder vollständiger Liste. ## Befund (geprüft gegen `1559f4b`, 9.0.0-beta.8) | Quelle | Was sie als Gates nennt | |---|---| | `AGENTS.md` § Gates (Z. 281, „Five limits are enforced in code…") | Mass-Update, Publish-Remote, Upload Review, Guideline Push, **Iteration Budget / Loop-Breaker** (Exit 1, nicht 42). **Kein rebase-review.** | | `instructions/gates.md` Z. 9 („**Two** limits are enforced in code…") | zwei - gemeint sind wohl die zwei Arten (Exit 42 und Budget), gezählt wird aber „limits" | | `instructions/gates.md` § Exit 42, Z. 37 („Five gates use it today") | Mass-Update, **rebase-review**, Publish-Remote, Upload Review, Guideline Push. Die Frontmatter-`description` nennt `sync` nicht. | | `docs/explanation/why-gates-are-code.md` Z. 3 und 37 („five hard limits", „The five gates ask four different kinds of question") | dieselben fünf wie `AGENTS.md`, kein rebase-review | | `Properties.gates` der Datensätze (→ `-h`, `tools/CONTRACT.md`, `docs/reference/exit-codes.md`) | `mass-update`, `publish-remote`, `rebase-review` (`git_publish.py:1341` `sync`, `:1513` `publish`), `upload-review` (`upload_cmd.py:165`), `guideline-push` (`export_cmd.py:253`), **`human-intervention-required (\`new project\` only)`** (`new_page.py:382`) | Drei Zählungen, drei verschiedene Mengen - Invariante 8 verletzt. `new` deklariert ein Pseudo-Gate, weil `CommandRecord.__post_init__` (`cli_contract.py:157`) eine Exit-42-`Failure` ohne `gates` verweigert; `new project` hat eine solche (`new_page.py:492`, `HumanInterventionRequired`). Das widerspricht `docs/explanation/why-gates-are-code.md` § „Exit 42 is a posture, and it outgrew the gates", die `HumanInterventionRequired` und die Preflight ausdrücklich als Exit 42 *ohne* Gate einordnet. ## Entscheidungen (Betreiber, 2026-10-07 - alle Empfehlungen angenommen) 1. **rebase-review ist ein Gate.** Es verweigert eine mögliche Operation, bis ein Mensch die Ausgabe gelesen hat, und wird per Token (`--confirm-rebase`) freigegeben - die Form des Mass-Update Gate. Anzeigename: **Rebase-Review Gate** (so auch in `gates.md`, das heute klein „rebase-review gate" schreibt). Die Erklärseite bekommt unter „Why different mechanisms, not one" einen Absatz zur Frage, die es stellt: *kollidiert das Eingehende logisch mit dem, was ich gleich veröffentliche?* - Token-Form, weil die Antwort je Rebase eine andere ist. 2. **Der Exit 42 von `new project` ist kein Gate** (Option b), wie die Erklärseite es schon sagt. `new_page.py` deklariert `gates=()`. `__post_init__` erlaubt eine Exit-42-Failure ohne Gate; die Generik-Zeile in `exit_status_entries` (Z. 371) bleibt unverändert, sie greift nur bei deklarierten Gates ohne explizite 42-Ursache. `new project` bleibt in `docs/reference/exit-codes.md` sichtbar, im Abschnitt „Exit 42 causes" (aus den `Failure`s erzeugt, `reference_doc.py` ab Z. 233). Verworfen: (a) als Gate aufnehmen, (c) anderer Exit-Code - beide widersprechen der Erklärseite. 3. **Die eine Liste ist `AGENTS.md` § Gates.** Normativ, in jeder Session geladen. § Gates nennt keine Zahl im Fließtext mehr, die schon beim nächsten Gate falsch wäre („Five limits" → eine Formulierung ohne Zahl). `instructions/gates.md` zählt nicht mehr selbst (Z. 9 und Z. 37 verlinken auf § Gates), behält aber die Prozedur je Gate. Die Erklärseite nennt keine Zahl mehr und verlinkt ebenfalls; ihre Aussage „vier Arten von Fragen" darf bleiben, wenn sie mit dem rebase-review-Absatz noch stimmt (sonst anpassen). 4. **Mechanisch gehalten, minimal:** - Register `GATES` in `tools/chemenu/cli_contract.py`: Datensatz-Name → Anzeigename in § Gates, plus ob das Gate mit 42 endet. Einträge: `mass-update` → „Mass-Update Gate", `publish-remote` → „Publish-Remote Gate", `rebase-review` → „Rebase-Review Gate", `upload-review` → „Upload Review Gate", `guideline-push` → „Guideline Push Gate" (alle Exit 42); `iteration-budget` → „Iteration Budget Gate / Loop-Breaker" (Exit 1, von keinem Datensatz deklariert - es gilt für alle). - `Properties` (bzw. `CommandRecord.__post_init__`) verweigert einen Gate-Namen, der nicht im Register steht, mit `ValueError` beim Import - so wie heute schon die Exit-42-Prüfung. - Neuer Check in `tools/chemenu/commands/docs_verify.py`: die fett gesetzten Eintragsnamen der Aufzählung in `AGENTS.md` § Gates (Muster `- **<Name>.**`) sind genau die Anzeigenamen des Registers, und jedes Exit-42-Gate des Registers wird von mindestens einem Datensatz deklariert. Neue `Failure` im `docs verify`-Datensatz (`docs_verify.py:1250`) mit Ursache und Reaktion. - Verworfen: § Gates aus dem Register generieren (Marker-Block in `AGENTS.md`) - zieht normative Prosa in Code, für sechs Zeilen zu viel Mechanik. ## Betroffene Dateien - `AGENTS.md` § Gates (Zählung raus, Eintrag **Rebase-Review Gate.**); dazu § File naming, wo die Erklärseite mit „the five gates" beschrieben war - `instructions/gates.md` (Z. 9, Z. 37, Anzeigename, Frontmatter-`description` um `sync` ergänzen) - `docs/explanation/why-gates-are-code.md` (Z. 3, Z. 37, Absatz für rebase-review) - `tools/chemenu/cli_contract.py` (Register `GATES`, Prüfung unbekannter Namen, `__post_init__` gelockert) - `tools/chemenu/commands/new_page.py` (Datensatz von `new`: `gates=()`) - `tools/chemenu/commands/docs_verify.py` (neuer Check + `Failure` im Datensatz) - `tools/chemenu/commands/git_publish.py` (Anzeigename „Rebase-Review Gate" in Hilfe- und Ursachentexten von `sync` und `publish`) - Tests: `tools/chemenu/tests/test_cli_contract.py` (unbekannter Gate-Name verweigert; Exit 42 ohne Gate zulässig), `tools/chemenu/tests/test_docs_verify.py` (neuer Check: fehlender und überzähliger Eintrag in § Gates, Exit-42-Gate ohne deklarierenden Datensatz); `test_reference_doc.py` nutzte einen Fixture-Gate-Namen `keep`, der nun `mass-update` heißt - veraltete Zählungen in Code-Kommentaren (`doctor.py`, `errors.py`, `git_publish.py`, `mcp/server.py`, `test_git_publish.py`) - danach `docs contract --apply` und `docs reference --apply` (regeneriert `tools/CONTRACT.md`, `docs/reference/exit-codes.md`, `docs/reference/commands/pages.md`) - Doc-Pull-Through nach `instructions/dev/doc-pull-through.md` (z. B. `docs/reference/`-Prosa, `README.md`, falls dort Gates gezählt werden) **Nicht im Umfang:** die `kb/`-Konzeptseiten (`Mass-Update Gate`, `Publish-Remote Gate` - „Drittes … Gate" -, `Iteration and Cost Limits`, `AGENTS.md`). Korpus, nachgezogen über die normale Ingest-Strecke. ## Version **MINOR** (neuer `docs verify`-Check). Kein Kommando, kein Flag, keine Datei-Form entfällt → in beide Richtungen drop-in. Der laufende Kandidat steht bereits auf 9.0.0 (MAJOR), `--minor` eskaliert also nichts. Umgesetzt als 9.0.0-beta.9; der Anzeigenamen-Nachzug im Abschluss ist ein `--patch` (9.0.0-beta.10). ## Akzeptanzkriterien - [x] Kein Dokument außer `AGENTS.md` § Gates zählt oder vollständig aufzählt die Gates; `AGENTS.md`, `instructions/gates.md` und `docs/explanation/why-gates-are-code.md` nennen keine Anzahl von Gates oder Limits (`rg -in "(two|three|four|five|six) (gates|limits|hard limits)"` über diese drei Dateien ist leer; zeilenübergreifend geprüft, `rg -U`). - [x] `AGENTS.md` § Gates führt das Rebase-Review Gate. - [x] Ein Datensatz mit einem Gate-Namen außerhalb des Registers scheitert beim Import mit `ValueError` (Test). - [x] Ein Datensatz mit Exit-42-`Failure` und ohne `gates` ist zulässig (Test); `new` deklariert kein Gate. - [x] `docs/reference/exit-codes.md` führt unter „Gates by command" genau `guideline-push`, `mass-update`, `publish-remote`, `rebase-review`, `upload-review`, und `new project` weiterhin unter „Exit 42 causes". - [x] `docs verify` scheitert, wenn in § Gates ein Registereintrag fehlt, ein Eintrag ohne Registereintrag steht, oder ein Exit-42-Gate von keinem Datensatz deklariert wird (Tests); auf dem Baum ist er grün. - [x] `tools/CONTRACT.md` und `docs/reference/` sind regeneriert. - [x] `pytest` (2554 bestanden, 3 übersprungen), `docs verify`, `instructions verify` lokal grün; CI grün auf `e9f4759` (Run 598 und 599) und auf `5915b07` (Run 600 und 601).
torben added the prio/plannedsize/Sarea/workflowkind/decision labels 2026-10-06 19:53:46 +00:00
Author
Owner

Changelog: Befund gegen 1559f4b geprüft und ergänzt: gates.md Z. 9 zählt eine dritte Menge („Two limits"), die Erklärseite nennt dieselben fünf wie AGENTS.md; der new-Eintrag ist durch CommandRecord.__post_init__ erzwungen und widerspricht why-gates-are-code.md § „Exit 42 is a posture". Zu jeder offenen Frage steht jetzt eine Empfehlung, die Fragen bleiben offen. Version präzisiert (PATCH/MINOR, Kandidat schon auf MAJOR). kb/-Konzeptseiten ausdrücklich aus dem Umfang genommen.

**Changelog:** Befund gegen `1559f4b` geprüft und ergänzt: `gates.md` Z. 9 zählt eine dritte Menge („Two limits"), die Erklärseite nennt dieselben fünf wie `AGENTS.md`; der `new`-Eintrag ist durch `CommandRecord.__post_init__` erzwungen und widerspricht `why-gates-are-code.md` § „Exit 42 is a posture". Zu jeder offenen Frage steht jetzt eine Empfehlung, die Fragen bleiben offen. Version präzisiert (PATCH/MINOR, Kandidat schon auf MAJOR). `kb/`-Konzeptseiten ausdrücklich aus dem Umfang genommen.
torben added size/Mkind/build and removed size/Skind/decision labels 2026-10-07 07:42:31 +00:00
Author
Owner

Changelog: Betreiber hat alle vier Empfehlungen angenommen; die offenen Fragen sind jetzt Entscheidungen. Register-Inhalt, Anzeigename „Rebase-Review Gate" und die Testfälle sind festgelegt; die Akzeptanzkriterien sind endgültig und prüfbar. Version auf MINOR festgelegt. Neu gelabelt: kind/decision → kind/build (entschieden), size/S → size/M (neuer Check mit eigenem Testaufwand, Instruction- und Contract-Änderung).

**Changelog:** Betreiber hat alle vier Empfehlungen angenommen; die offenen Fragen sind jetzt Entscheidungen. Register-Inhalt, Anzeigename „Rebase-Review Gate" und die Testfälle sind festgelegt; die Akzeptanzkriterien sind endgültig und prüfbar. Version auf MINOR festgelegt. Neu gelabelt: `kind/decision` → `kind/build` (entschieden), `size/S` → `size/M` (neuer Check mit eigenem Testaufwand, Instruction- und Contract-Änderung).
Author
Owner

Changelog: AGENTS.md § Gates ist jetzt die eine Gate-Liste und führt das Rebase-Review Gate; gates.md und die Erklärseite verlinken darauf, statt zu zählen. cli_contract.GATES registriert die Gates, ein unbekannter Gate-Name scheitert beim Import, und docs verify vergleicht § Gates mit dem Register. new deklariert kein Pseudo-Gate mehr (new project steht unter „Exit 42 causes"). Veröffentlicht als 9.0.0-beta.9 (e9f4759), CI grün (Run 598, 599).

**Changelog:** `AGENTS.md` § Gates ist jetzt die eine Gate-Liste und führt das Rebase-Review Gate; `gates.md` und die Erklärseite verlinken darauf, statt zu zählen. `cli_contract.GATES` registriert die Gates, ein unbekannter Gate-Name scheitert beim Import, und `docs verify` vergleicht § Gates mit dem Register. `new` deklariert kein Pseudo-Gate mehr (`new project` steht unter „Exit 42 causes"). Veröffentlicht als 9.0.0-beta.9 (`e9f4759`), CI grün (Run 598, 599).
Author
Owner

Changelog: Abschluss. Die Hilfe- und Ursachentexte von sync und publish nennen das Gate jetzt „Rebase-Review Gate" (9.0.0-beta.10, 5915b07, CI grün: Run 600, 601); die übrigen Dokumente wurden gegen die Änderung gelesen, keines zählt oder listet die Gates mehr. Der Rest steht im Kommentar zum Hauptbau (9.0.0-beta.9, e9f4759). Issue geschlossen.

**Changelog:** Abschluss. Die Hilfe- und Ursachentexte von `sync` und `publish` nennen das Gate jetzt „Rebase-Review Gate" (9.0.0-beta.10, `5915b07`, CI grün: Run 600, 601); die übrigen Dokumente wurden gegen die Änderung gelesen, keines zählt oder listet die Gates mehr. Der Rest steht im Kommentar zum Hauptbau (9.0.0-beta.9, `e9f4759`). Issue geschlossen.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: torben/chemenu#194