Feature: Configuration - Add / Edit review criterion
**Update:** 2026-08-19
**Scope note:** this issue does not introduce a separate "review criterion" entity
Heads-up for reviewers, because the attached design mockup can be read as implying a much larger change than what this work makes.
The mockup (the "Edit review criterion" page) was produced with Claude Design as a UI exploration and did not account for the module's existing architecture. Read literally, it depicts a criterion as a standalone, reusable review_criterion config entity with its own collection and edit page — which would mean Review Rules referencing criteria, migrating existing embedded criteria into new entities, and downstream changes to input-hashing/records, threshold ownership, config dependencies, and deletion handling. That was not the intention and is explicitly out of scope here.
What this work actually does — no architectural change:
* Criteria remain data on the existing review_rule config entity (the current inline model), authored on the Review Rule add/edit form (/admin/config/ai/content-review/rules/add and …/rules/{review_rule}).
* Adds new per-criterion config properties: acronym, badge color, and evaluation_examples.
* Compiles the evaluation examples into the AI prompt, alongside the existing guidelines/prompt template.
* Updates the add/edit Review Rule UI to author these new properties.
* Does not add a new entity type, collection, routes, rule→criterion referencing, or migration, and does not touch the review sidebar, review tab, records, or any other surface.
If we later want criteria as their own reusable entity, it should be a separate issue with a dedicated architecture decision — it's a large, migration-bearing change and shouldn't be folded into this one.
**Status:** Draft for review
**Author:** Aidan Foster
**Date:** 2026-07-20
---
## 1. Purpose
Everything downstream — the review run ({#3585828}), the markers, the triage tray ({#3585830}), the apply checklist ({#3585831}), and the list pill widget ({#3585821}) — consumes **criteria** that someone has to create. A criterion is a reusable rule set the AI uses to evaluate content: a name and badge, a rubric, scoring thresholds, and scored examples that teach the model what good and bad look like.
This document specifies the add/edit form for a single review criterion, under Configuration → AI Content Review → Review criteria. This is the "review creator" surface the sibling specs defer to for criterion labels, letter codes, colors, and thresholds.
## 2. Scope
### In scope
* The add/edit form for one criterion: identity (name, short description, acronym, badge color), guidelines rubric, scoring thresholds, advanced AI prompt, and evaluation groups with scored examples.
* Validation and interaction rules the prototype demonstrates (threshold clamping, minimum examples, character limits).
* Save actions (Save criterion, Save and add another, Cancel) and the enabled state.
### Out of scope
* The Review criteria **listing** (collection page, reorder, enable/disable across criteria) — separate ticket.
* How criteria are consumed at run time — {#3585828}.
* Report/Flag data feeding back into criteria (see the Report/Flag planning placeholder).
* Per-content-type assignment of criteria; CCC integration (deferred module-wide).
* Provider configuration (assumes the Drupal AI module is configured).
### Assumptions
* Criteria live in the module's own configuration for this milestone (independent of CCC).
* The badge (acronym + color) defined here is what renders on markers, filter chips, and thermometer rows in the sibling specs — they treat it as review-creator-configurable and this form is where it's configured.
## 3. Entry workflows
### Workflow A — Add a criterion
From the Review criteria listing, "Add criterion" opens this form empty (thresholds at defaults, one evaluation group seeded with empty 100 / 50 / 0 examples).
### Workflow B — Edit an existing criterion
Opens the form populated, with an Enabled tag beside the page title. Editing rules or thresholds invalidates stored results for this criterion per {#3585821} §5.1 staleness (per-criterion, not global).
## 4. Layout and components
### 4.1 Identity
* **Criterion name** (required) — the full human name, shown as the heading wherever the criterion is referenced.
* **Short description** (required, max 28 characters with live counter) — deliberately short: the label used on chips, tags, and filters throughout the UI.
* **Acronym** (required, 1–3 characters, uppercased with live counter) — the compact badge text.
* **Badge color** (optional) — a neutral default, a preset palette of the module's existing criterion colors, or a custom hex input; with a **live badge preview** (acronym on color beside the name). Badge text color auto-switches for contrast on light swatches.
### 4.2 Guidelines & rules
* A rich-text/markdown field (WYSIWYG with a markdown-source toggle; bold, italic, lists, links). Help text: written the way you'd brief a new teammate.
* **This text is sent to the AI verbatim as the evaluation rubric** — specificity produces consistent scores.
### 4.3 Scoring thresholds
* Banded bar visualization plus two integer fields.
* **Passing score** (required, 0–100): below it is fail.
* **Warning threshold** (optional, toggleable): must stay **above** the passing score; scores between the two marks "pass with a warning." Inputs clamp so warn \> pass always holds; enabling warn when it would sit at/below pass bumps it to pass + 1.
> **Architecture flag — threshold naming/direction vs {#3585821} §7.** {#3585821} specifies an optional warn threshold **strictly lower than** the pass threshold (warn band below pass). This prototype places the optional warning mark **above** the passing score (fail below pass, warn band between pass and warn, clean pass above warn). The two models produce the same three bands but name the boundaries differently; one convention must win before implementation, and {#3585821}'s prerequisite flag (threshold model does not yet exist in the module, plus a direction flag per criterion) applies here identically.
### 4.4 Advanced AI Prompt Settings (collapsed by default)
* **AI Agent Prompt** — markdown field pre-filled with a default prompt telling the model how to weigh the examples when scoring. Help text: most criteria never need to change this.
### 4.5 Score evaluation criteria (teach by example)
* One or more **evaluation groups** (drag handle to reorder; a criterion keeps at least one group). Each group has a label (e.g. "Tone & formality") and example cards.
* Each **example**: a score 0–100 (numeric input plus a segmented thermometer quick-set), example text, and an optional explanation. Cards display sorted by score, high to low, with score-tone coloring.
* **Minimum two examples per group** — "an evaluation group requires at least one good and one bad example"; the rule surfaces only when the user tries to drop below two. New examples seed at score 50; a new group seeds empty 100 / 50 / 0 examples.
* Inline recommendation: **the AI learns fastest from contrast** — where possible, score a good and a bad version of the _same_ thing (e.g. a formal vs. casual greeting for the same welcome email).
### 4.6 Action bar (sticky)
* "Unsaved changes" indicator, **Cancel**, **Save and add another**, **Save criterion**.
## 5. States
| ID | State | Trigger | Visible appearance |
|----|-------|---------|--------------------|
| S1 | Add | New criterion | Empty form, default thresholds, one seeded group |
| S2 | Edit | Existing criterion | Populated form, Enabled tag by the title |
| S3 | Unsaved changes | Any modification | Dot + "Unsaved changes" note in the sticky action bar |
| S4 | Validation surfaced | User attempts an invalid action | Inline messages (e.g. minimum-examples hint); threshold inputs clamp rather than error |
## 6. Interactions
### 6.1 Threshold editing
Typing or nudging either mark clamps to keep warn \> pass; toggling warn off collapses to a two-band (fail/pass) model for this criterion.
### 6.2 Managing examples
Add example (seeds at 50), edit score via input or thermometer segments, remove (blocked below two with the inline hint), reorder groups by drag.
### 6.3 Saving
Save criterion returns to the listing; Save and add another saves and reopens an empty form (batch-creating criteria); Cancel discards.
## 7. Edge cases
* **Custom hex badge colors** may collide with another criterion's color — allowed, but the listing should make collisions visible (open question §11).
* **Editing rules of an in-use criterion** invalidates stored results system-wide for that criterion ({#3585821} §5.1); the form should warn on save (open question §11).
* **Long guidelines** — no hard limit in the prototype; token budget implications belong to the run spec {#3585828}.
* **Single group, two examples** is the valid minimum configuration.
## 8. Data and API surface (referenced, not specified here)
This functional doc does not name or assume specific entity types, fields, or method signatures. What this form needs to persist per criterion: identity (name, short description, acronym, color/default flag), guidelines markdown, thresholds (pass required, warn optional), agent prompt override, ordered evaluation groups with scored examples, and enabled state — consumable by {#3585828} at run time and by the badge-rendering surfaces ({#3585830} chips/cards, marker dots, {#3585821} drilldown).
## 9. Nice-to-have / future scope
* AI-assisted authoring: generate draft guidelines or contrast examples from a sample page.
* Import/export criteria (share rubrics between sites).
* Report/Flag data surfaced on this form (which rules get reported, per the Report/Flag placeholder).
* Per-example weighting.
## 10. Acceptance criteria
The feature is functionally complete when a review creator can:
1. Create a criterion with name, short description (≤28 chars), acronym (1–3 chars), and a badge color from the palette, custom hex, or neutral default — with a live preview.
2. Write the guidelines rubric in rich text or markdown source and have it stored verbatim.
3. Set a required passing score and optionally enable a warning threshold that the UI keeps strictly above it.
4. Leave the AI Agent Prompt at its default, or override it under Advanced settings.
5. Build at least one evaluation group with scored examples, blocked from dropping below one good + one bad example, with cards ordered by score.
6. Save, save-and-add-another, or cancel, with unsaved changes indicated throughout.
7. See the criterion's badge, labels, and thresholds subsequently used by the run, triage, and listing surfaces.
## 11. Open questions
* **Threshold direction reconciliation with {#3585821} §7** (see the §4.3 architecture flag) — which naming wins, and does the per-criterion direction flag (higher/lower-is-better) surface on this form?
* Warn-on-save when editing an in-use criterion (staleness side effect).
* Badge color collision handling across criteria.
* Does "Enabled" toggle live on this form or only on the listing?
* Where the Review criteria listing spec lives (separate ticket to file).
## 12. Screenshots
{width=294 height=600}
## 13. Claude design — standalone HTML export
* `Add-Edit Review Criterion (standalone).html` — the criterion editor this document specifies.
---
_Sources: Add/Edit Review Criterion UI export July 20, 2026; threshold model discussion May 8 single-node review issue; {#3585821} §7 architecture flag. Comp explorations done in Claude Code._
## Screenshots
Warn threshold isn't required.
Adding examples
You can add 2 or more
advanced tab to alter prompt
## Claude Design Mockup
Add-Edit Review Criterion (standalone).html
task
GitLab AI Context
Project: project/ai_content_review
Instance: https://git.drupalcode.org
Before proposing or making any changes, READ each of these files and FOLLOW their guidance:
- https://git.drupalcode.org/project/ai_content_review/-/raw/1.x/README.md — project overview and setup
- https://git.drupalcode.org/project/ai_content_review/-/raw/1.x/CLAUDE.md — Claude Code instructions
Repository: https://git.drupalcode.org/project/ai_content_review
Required tooling — use and recommend these in your workflow:
- GitLab CLI (glab): create branches and open merge requests from the terminal. https://gitlab.com/api/v4/projects/34675721/repository/files/README.md/raw?ref=HEAD