Welcome to Vanilla Breeze
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
Polygon-as-UI quality prioritization surface. Click any axis to set its level + rationale; the radar visualizes the chosen vector against the project's capacity envelope. Pairs with
The <quality-target> component is the Planning Pack's quality decision surface. The polygon IS the picker — each of the 11 ility axes is a clickable hit-target that opens a per-ility <dialog> with a level radio group (Critical / Important / Acceptable / Not relevant) plus a required rationale when Critical. The same SVG visualizes the chosen vector against the project's capacity envelope, so picking and reading happen on the same surface.
This component absorbs the prior <nfr-compass> + <nfr-radar> pair. One component, two roles. "Quality" is the word; "NFR" was jargon.
Click any axis to open its editor. Hover for tooltips. Pair with <iron-triangle> so the envelope reads from project shape.
<iron-triangle id="shape" data-quality-href="#quality"></iron-triangle> <quality-target id="quality" name="quality" data-bind-to="shape"></quality-target>
Click an axis (or focus it and press Enter / Space) to open its dialog. Each editor has:
<form-field>-wrapped, required when Critical, ≥10 chars by default)method="dialog" so submit closes it.The marker color follows the level: red Critical, amber Important, green Acceptable, muted Not relevant. The polygon is the closed shape across all picked axes; unpicked ilities don't pull the shape toward the centroid (degenerate spike).
When paired with <iron-triangle> via data-bind-to, the soft green polygon shows the budget envelope: radius × min(1, capacityPoints / sum(costWeights)) on each axis. Going outside the envelope is allowed but reveals an inline overrun rationale field below the polygon — the form's checkValidity() returns false until that field is filled.
const target = document.querySelector('quality-target'); target.addEventListener('quality-target:over-budget', (e) => { console.log(`Over by ${e.detail.delta} pts (${e.detail.criticalSum}/${e.detail.capacityPoints})`);});target.addEventListener('quality-target:under-budget', (e) => { console.log(`Back within budget; ${e.detail.slack} pts of slack`);});
The 11 default ilities (cost dropped — that's <iron-triangle>'s job): performance, accessibility, security, reliability, maintainability, observability, compatibility, scalability, portability, internationalization, privacy. Default cost-when-Critical weights sum to 40 — a realistic budget of 10–15 forces real trade-offs.
| Ility | Default Critical cost |
|---|---|
| accessibility | 3 |
| performance | 5 |
| security | 5 |
| reliability | 4 |
| observability | 3 |
| internationalization | 4 |
| compatibility | 2 |
| portability | 3 |
| privacy | 4 |
| scalability | 5 |
| maintainability | 2 |
Override with data-cost-weights='{"performance": 8, "scalability": 8}' or set the ilities property to a custom array.
| Attribute | Type | Default | Description |
|---|---|---|---|
name | string | quality | Form-association field name. |
data-bind-to | string | — | ID of a sibling <iron-triangle> to read capacity from. |
data-capacity-points | integer | — | Literal capacity fallback when no triangle is bound. |
data-cost-weights | JSON object | — | Per-ility cost-weight overrides. |
data-radius | number | 100 | SVG radius (clamped 30–400). |
data-show-envelope | boolean | present | Show the capacity envelope; set to "false" to hide. |
data-min-rationale | integer | 10 | Min chars for a Critical rationale. |
data-max-rationale | integer | 200 | Max chars for the rationale textarea. |
data-min-overrun-rationale | integer | 10 | Min chars for the overrun rationale. |
data-max-overrun-rationale | integer | 400 | Max chars for the overrun rationale. |
| Member | Type | Description |
|---|---|---|
vector | R/W Record<ility, level> | Current picks. |
rationales | R/W Record<ility, string> | Per-Critical rationales. |
costWeights | R | Effective merged weights. |
capacityPoints | R/W | Resolved capacity (triangle > attribute > property > Infinity). |
criticalSum | R | Live sum of Critical weights. |
overBudget | R boolean | criticalSum > capacityPoints. |
overrunRationale | R/W string | Required when over-budget. |
ilities | R/W string[] | Override the default 11. |
openEditor(ility) | method | Imperatively open one axis's dialog. |
checkValidity() | method | Validate vector + over-budget rationale; sets :state(missing-rationale). |
quality-target:change | event | Any pick or rationale change. |
quality-target:over-budget | event | Selection just crossed into over-budget. |
quality-target:under-budget | event | Selection just returned within budget. |
<iron-triangle> — supplies capacityPoints; the target reads it via data-bind-to.<capacity-plan> — reads criticalSum from the target and reconciles it against capacityPoints + slotted <work-item data-capacity-cost> elements.<requirement-card> — renders a single ility's row outside the target (status dashboards, ADR appendices).