Trust
The whole proof machinery, in the open: every promise in a registry with its gate and its negative control, a mutation score measured over the full suite, and every decision and lesson on record. Nothing on this page is typed — it is read from the repository at build time.
83
of 98 promises enforced — 15 partial, 0 gaps, each with a recorded deadline
88.86%
mutation score — 10012 of 11267 mutants killed by the unit suite
29
hand-written gates, each with a negative control proving it can fire
103
decision records · 257 logged lessons
The conformance report
WCAG 2.2, levels A and AA, one row per criterion — rendered from the gates below and never typed, and honest about the one pass no gate can run: the Accessibility Conformance Report.
The gates
Every gate reads tracked files and runs in CI; a promise without a gate does not ship. By name:
acrariabenchbridgebrowsersbundleconsumercoveragedistancedocsfilesflakeformsharnessiconsindexlanguagemutationpartsprosereachsincestylessupporttextstokenstoolstypecheckzoneless
The promise registry
One row per requirement: the promise it makes, the gate that holds it and the negative control that proves the gate can fire. The component cards link straight into these anchors.
axis
| requirement | state | gate | control |
|---|---|---|---|
req-axisNothing breaks silently | enforced | req-quality-registry — the promise → gate → control registry, read … | req-quality-negative-control — the rule that a gate without proof o… |
accessibility
| requirement | state | gate | control |
|---|---|---|---|
req-a11y-wcagWCAG 2.2 AA as the minimum | enforced | req-a11y-axe (the rendered DOM) + req-token-contrast (the values … | see both gates above > **Formal conformance does not mean good qualit… |
req-a11y-built-inAccessibility built into the component | enforced | libs/components/*/src/*.spec.ts — ARIA relations checked per compon… | `a11y.spec.ts › "the a11y gate really does detect violations (a contr… |
req-a11y-touchTouch target ≥ 24×24 px, outright | enforced | apps/sandbox-e2e/src/field-hitarea.spec.ts, `apps/sandbox-e2e/src/c… | the gate has two documented runs in which it fired: lesson-25 (a wr… |
req-a11y-axeAutomated axe-core audit | enforced | apps/sandbox-e2e/src/a11y.spec.ts — every audit reads the page at *… | `a11y.spec.ts › "the a11y gate really does detect violations (a contr… |
req-a11y-motionReduced motion is a token axis, not a rule in a stylesheet | enforced | apps/sandbox-e2e/src/preferences.spec.ts — the axis itself, in the … | `preferences.spec.ts › "with no preference the motion axis stands at … |
req-a11y-forced-colorsForced colours mode | enforced | apps/sandbox-e2e/src/forced-colors.spec.ts — what the browser paint… | emulation goes through page.emulateMedia() in the visit() helper,… |
req-a11y-acrThe conformance report is rendered from the gates | enforced | tools/check-acr.mjs — eight points: the catalogue is the standard's… | tools/check-acr.fixtures/ — one hundred and eighty-two prepared inp… |
API
| requirement | state | gate | control |
|---|---|---|---|
req-api-namesNaming per the new style guide | partial | libs/components/eslint.config.mjs — `@angular-eslint/component-sele… | none — deliberately: an ESLint rule has no quiet-pass mode --- |
req-api-foundationStandalone, OnPush, zoneless-safe | enforced | tools/check-zoneless.mjs (target check-zoneless, in CI) — measuri… | tools/check-zoneless.fixtures/ — doctored inputs, one per way of di… |
req-api-signalsInputs and outputs through signals | partial | libs/components/button/src/button.spec.ts, `libs/components/checkbo… | none — deliberately: a wrong transform shows up as a wrong type in th… |
req-api-attributesState as data-pct-*, not CSS classes | partial | apps/sandbox-e2e/src/states.spec.ts — the cross-cutting states view… | none — deliberately: a selector matching nothing yields an empty loca… |
req-api-configGlobal configuration via providePctConfig | partial | libs/components/button/src/button.spec.ts — the default size from… | none — deliberately: the test compares two different values, so i… |
req-api-signal-formsControls are native signal-forms controls | enforced | tools/check-forms.mjs (target check-forms in the root project, in… | the tests start from a non-empty initial value — with an empty mo… |
req-api-dayA day is a calendar day, the same in every timezone | enforced | libs/components/date/src/day.spec.ts › in a hostile timezone — the … | the same cases build the day the old way beside the new — `new Date(2… |
req-api-timeA time of day is a wall clock, the same in every timezone | enforced | libs/components/time/src/time.spec.ts › in a hostile timezone — the… | the same cases build the time the old way beside the new — in Warsaw … |
req-api-datetimeA day with a time is a wall clock with a date, the same in every timezone | enforced | `libs/components/datetime/src/datetime.spec.ts › in a hostile timezon… | the same cases build the pair the old way beside the new — in Warsaw … |
req-api-containerIn a composite component the control is the container | partial | libs/components/radio/src/radio.spec.ts | none — deliberately: the violation would be a second `FormValueContro… |
req-api-wrapperForm controls are a wrapper plus a control | enforced | libs/components/field/src/field.spec.ts — the chrome's own cases pl… | field-hitarea.spec.ts — a cursor map over a grid of points (`elemen… |
req-api-no-wrapperThe wrapper is optional | partial | libs/components/field/src/field-controls.spec.ts — every control is… | none — deliberately: the standalone mode is the default, so its f… |
req-api-messageOne message line, and the error takes it | enforced | libs/components/field/src/field-controls.spec.ts — the controls tha… | tools/check-aria.fixtures/hint-beside-error — the same two messages… |
req-api-warningA warning stands where an error would, and vetoes nothing | enforced | libs/components/core/src/warnings.spec.ts — the seven cases of 0087… | libs/components/core/src/warnings.spec.ts › "one validator, as an e… |
req-api-frameThe control tells the wrapper whether it wants a frame | enforced | apps/sandbox-e2e/src/field.spec.ts, req-a11y-touch | the touch-target test caught the regression described in lesson-25 … |
req-api-native-inputThe text field stands on a native <input> | partial | libs/components/field/src/field-controls.spec.ts | none — deliberately: swapping <input> for an element of our own kno… |
req-api-platformWe do not implement what the platform gives us | enforced | apps/sandbox-e2e/src/radio.spec.ts — keyboard navigation; `apps/san… | the keyboard half has none — deliberately: a navigation test has no m… |
req-api-numberThe number field does not stand on <input type="number"> | enforced | libs/components/field/src/number.spec.ts, `apps/sandbox-e2e/src/num… | recorded rather than prepared, because each mechanism is one line and… |
req-api-genericA choice control's value is of type T, not a string | enforced | libs/components/select/src/select.spec.ts — the generic contract, p… | the probe from lesson-37 — five deliberately contradictory bindings… |
req-api-partsThe data-pct-part contract is public styling API | enforced | tools/check-parts.mjs (target check-parts in the root project, in… | tools/check-parts.fixtures/ — 87 inputs, each rejected on its own p… |
req-api-parts-uniquePart names are unambiguous under nesting | enforced | tools/check-parts.mjs point 6 — a component whose parts share a pre… | tools/check-parts.fixtures/part-outside-namespace, and a run agains… |
req-api-harnessA harness per component, on the parts contract | enforced | tools/check-harness.mjs (target check-harness in the components… | tools/check-harness.fixtures/ — 27 prepared inputs, each rejected o… |
req-api-templatesCustomisation through projection and templates | enforced | libs/components/core/src/core.spec.ts — pctReportOrphanSlot under… | two recorded runs that fail on different cases. pctReportOrphanSlot… |
req-api-iconsEasy use of somebody else's icons | enforced | tools/check-icons.mjs (target check-icons) — six points over the … | tools/check-icons.fixtures/ — thirty-two prepared inputs, each reje… |
req-api-icons-customThe library ships no icon set of its own | partial | libs/components/check-package.mjs — the absence of icon files in th… | none — deliberately: the violation here is adding something, not … |
req-api-textsThe library's strings are exposed for translation | enforced | tools/check-texts.mjs (target check-texts) — six points: a string… | tools/check-texts.fixtures/ — 113 doctored inputs, each rejected on… |
req-api-catalogueThe contract is machine-readable, from the same sources as the pages | enforced | apps/docs/tools/build-content.mjs (target content of the docs p… | the content pass's tripwires fired twice while the cards' owed readin… |
req-api-overlayThe overlay comes out of the control's visible edge | enforced | apps/sandbox-e2e/src/select.spec.ts — measuring the panel's width a… | the measurement from lesson-35 (a 301 px field ⇒ a 275 px panel, of… |
req-api-sizeSize is one axis for the whole library | enforced | apps/sandbox-e2e/src/size.spec.ts — measured in the browser | the test checks that the heights are equal *_and what that height is_… |
req-api-animationsAnimation without @angular/animations | enforced | libs/components/check-package.mjs point 7, rule forbidden — the b… | tools/check-package.fixtures/ — five prepared packages, each reject… |
project
| requirement | state | gate | control |
|---|---|---|---|
req-project-monorepoThe workspace is an NX monorepo | partial | .github/workflows/ci.yml — the entire run goes through nx affected | none — deliberately: the failure is immediate and total (CI has nothi… |
req-project-latestBefore 1.0 the newest versions; from the first release, the matrix | enforced | tools/check-support.mjs (point 2) — the declared Angular window equ… | tools/check-support.fixtures/window-narrower-than-the-manifest.json… |
req-project-dependenciesMinimum runtime dependencies | enforced | point 7 of libs/components/check-package.mjs, over the packed m… | tools/check-package.fixtures/ — nine prepared packages for point 7 … |
req-project-appsWhat lives in the workspace | enforced | apps/docs/project.json, apps/docs-e2e/project.json — the two proj… | `apps/docs-e2e/src/shell.spec.ts › "renders the home page from the li… |
req-project-packageOne npm package | enforced | libs/components/check-package.mjs (target check-package, in CI) —… | tools/check-package.fixtures/ — a doctored package for every point … |
req-project-entrypointsSecondary entrypoints canonically through ng-packagr | enforced | libs/components/check-package.mjs — the exports map in the packed… | tools/check-package.fixtures/theme-outside-exports/ — a file presen… |
req-project-coreShared code in core | partial | libs/components/field/src/field-controls.spec.ts — the shared messa… | none — deliberately: the violation here is duplication, not a fai… |
req-project-tokens-libTokens are a separate library | enforced | libs/components/project.json → implicitDependencies: ["tokens"] +… | tools/check-package.fixtures/theme-missing/ — a package without `th… |
req-project-tree-shakingThe primary entrypoint is minimal | enforced | tools/check-bundle.mjs (target check-bundle in components, in C… | tools/check-bundle.fixtures/ — 47 doctored inputs, each rejected on… |
req-project-filesA fixed component file structure | enforced | tools/check-files.mjs (target check-files, in CI) — ten points ov… | tools/check-files.fixtures/ — 49 prepared trees, each rejected on i… |
req-project-prefixThe pct prefix | partial | libs/components/eslint.config.mjs — the `@angular-eslint/component-… | none — deliberately: an ESLint rule fires on the first violation and … |
req-project-languageThe repository speaks one language: English | enforced | tools/check-language.mjs (target check-language in the root proje… | tools/check-language.fixtures/ — 35 doctored inputs, each rejected … |
req-project-conciseText in the repository carries weight | enforced | tools/check-prose.mjs (target check-prose in the root project, in… | tools/check-prose.fixtures/ — fifty-five prepared inputs, each reje… |
req-project-angularThe newest Angular mechanisms | enforced | tools/check-zoneless.mjs (target check-zoneless, in CI) — three p… | tools/check-zoneless.fixtures/ — doctored inputs, one per way for z… |
req-project-ssrComponents work under SSR | enforced | apps/sandbox-e2e/src/hydration.spec.ts — the check sits in the `vis… | `hydration.spec.ts › "the gate really does detect a hydration error (… |
req-project-layoutDirectory layout | partial | apps/docs/project.json, apps/sandbox/project.json, `apps/sandbox-… | none — deliberately: the violation is immediate and total — a project… |
req-project-reachEvery tracked file has a reader | enforced | tools/check-reach.mjs (target check-reach in the root project, in… | tools/check-reach.fixtures/ — 33 prepared inputs, each rejected on … |
quality
| requirement | state | gate | control |
|---|---|---|---|
req-quality-negative-controlEvery gate has a negative control | enforced | tools/check-docs.mjs — the Control field is required on every r… | tools/check-docs.fixtures/ — a requirement with a gate but no contr… |
req-quality-inheritanceA gate that reads a class reads the whole of it | enforced | the list, one entry per gate that reads a class: `tools/check-aria.mj… | tools/check-aria.fixtures/base-not-read/, `tools/check-texts.fixtur… |
req-quality-registryThe promise → gate → control registry | enforced | tools/check-docs.mjs (target check-docs, in CI) — the six checks … | tools/check-docs.fixtures/ — a set of deliberately broken requireme… |
req-quality-indexA list that describes a directory is derived from it | enforced | tools/check-index.mjs (target check-index in the root project, in… | tools/check-index.fixtures/ — 23 prepared inputs, each rejected on … |
req-quality-typecheckEvery project has a typecheck target | enforced | tools/check-typecheck.mjs (target check-typecheck, in CI) — four … | tools/check-typecheck.fixtures/ — eleven doctored inputs, each reje… |
req-quality-unitUnit tests on Vitest | enforced | in three parts, because "the tests run", "how many pass" and "how man… | tools/check-mutation.fixtures/ — 91 doctored inputs on a fake libra… |
req-quality-coverageCoverage ≥ 80% of lines | enforced | in three parts, because the percentage, its denominator and the templ… | tools/check-coverage.fixtures/ — twenty-two doctored inputs, one pe… |
req-quality-e2ee2e tests on Playwright, visual ones included | enforced | apps/sandbox-e2e/src/visual.spec.ts and the remaining e2e specs; an… | there are two thresholds and both come from measurement. The pixe… |
req-quality-hydrationA hydration gate in e2e | enforced | apps/sandbox-e2e/src/hydration.spec.ts + the visit() helper in `a… | `hydration.spec.ts › "the gate really does detect a hydration error (… |
req-quality-packageA gate that examines the packed artifact | enforced | libs/components/check-package.mjs (target check-package, in CI) | tools/check-package.fixtures/ — seven doctored packages, one per po… |
req-quality-consumerA consumer test on a local registry | enforced | tools/check-consumer.mjs (target check-consumer, in CI) — seven p… | tools/check-consumer.fixtures/ — 28 doctored inputs, each rejected … |
req-quality-browsersThe browser matrix | enforced | apps/sandbox-e2e/playwright.config.mts — three projects (chromium, … | tools/check-browsers.fixtures/ — 44 doctored inputs, each rejected … |
req-quality-benchmarkWhat a component costs is a published number | enforced | tools/check-bench.mjs (target check-bench of the docs project, … | tools/check-bench.fixtures/ — 17 prepared inputs, each rejected on … |
req-quality-viewsThe sandbox is split into views | enforced | apps/sandbox-e2e/src/a11y.spec.ts, hydration.spec.ts — both itera… | apps/sandbox/src/app/app.spec.ts — the view registry against the ro… |
req-quality-cardThe shared sbx-demo card | enforced | apps/sandbox/src/app/ui/demo.spec.ts; tools/check-docs.mjs — ever… | tools/check-docs.fixtures/ — a card with a non-existent identifier … |
req-quality-stageThe page theme is a scoped theme too | enforced | apps/sandbox-e2e/src/theme.spec.ts, `apps/sandbox-e2e/src/shell.spe… | `preferences.spec.ts › "with no dark preference :root stays light (th… |
req-quality-prefixSandbox infrastructure uses the sbx prefix | partial | apps/sandbox/eslint.config.mjs — selector rules with the prefixes | none — deliberately: an ESLint rule has no quiet-pass mode |
release
| requirement | state | gate | control |
|---|---|---|---|
req-release-semverSemVer with pre-release channels | enforced | libs/components/check-package.mjs (point 4: PCT_VERSION == `versi… | stamp-version is not a dependency of build — if it were, the … |
req-release-ng-addng add and the migration collection | enforced | libs/components/check-package.mjs (point 5) — the collections are i… | tools/check-package.fixtures/schematic-missing/ — a package whose c… |
req-release-metadataThe package carries complete metadata | enforced | libs/components/check-package.mjs (point 6) — two different severit… | tools/check-package.fixtures/repository-missing/ — a manifest witho… |
req-release-supportSupport and deprecation policy | enforced | tools/check-support.mjs (five points) over docs/support.md, which… | tools/check-support.fixtures/ — fifteen prepared inputs, each rejec… |
req-release-sinceThe public surface says since when | enforced | tools/check-since.mjs (points 1–4: every item dated; a value that i… | tools/check-since.fixtures/ — seven prepared inputs, each rejected … |
tokens
| requirement | state | gate | control |
|---|---|---|---|
req-token-dtcgThe source of truth is the DTCG format | partial | libs/tokens/build.mjs — the build will not start on a malformed sou… | none — deliberately: a parse error is immediate and loud |
req-token-bridgeThe sources round-trip through Tokens Studio | enforced | tools/check-bridge.mjs (target check-bridge in the root project, … | tools/check-bridge.fixtures/ — 19 prepared inputs, each rejected on… |
req-token-artifactsThe build generates artifacts from the source | enforced | the typecheck target of the sandbox-e2e project — the tokenOf /… | swapping one name for a wrong one produces 6 type errors — a run docu… |
req-token-tiersThree tiers of tokens | enforced | tools/check-tokens.mjs (target check-tokens in the root project, … | tools/check-tokens.fixtures/ — one input per rule: `colour-under-se… |
req-token-referencesReferences stay as var() | enforced | apps/sandbox-e2e/src/theme.spec.ts — overriding a semantic token ch… | the test compares the component token in :root and in a scope —… |
req-token-closureA theme block contains the transitive closure | enforced | apps/sandbox-e2e/src/theme.spec.ts — a component token compared… | the run from lesson-17: before the fix --pct-surface was correctl… |
req-token-namesA token name can be guessed | enforced | tools/check-tokens.mjs (target check-tokens in the root project, … | tools/check-tokens.fixtures/ — 34 inputs, each rejected on its own … |
req-token-text-pairsA surface has a matching text token | enforced | tools/check-tokens.mjs (target check-tokens in the root project, … | tools/check-tokens.fixtures/ — unmeasured-colour (a stylesheet pa… |
req-token-contrastThe contrast gate as a skin policy | enforced | libs/tokens/build.mjs (target tokens:build, in CI through `^build… | the run from lesson-6: the original guard let disabled through at… |
req-token-no-opacityStates do not use opacity | enforced | tools/check-styles.mjs (target check-styles, in CI) — point 6: `o… | tools/check-styles.fixtures/partial-opacity/ (a state expressed thr… |
req-token-cssTokens compile to native custom properties | enforced | apps/sandbox-e2e/src/theme.spec.ts, `libs/components/check-package.… | tools/check-package.fixtures/token-without-declaration/ — a package… |
req-token-scssInternally we use SCSS | partial | none — deliberately: the file extension is visible in review, and a s… | not applicable --- |
req-token-overrideTokens can be overridden for chosen components | enforced | apps/sandbox-e2e/src/theme.spec.ts | as in req-token-closure — comparing the component token, not the se… |
req-token-layersThe stacking order is a list, and every number in it is read | enforced | tools/check-tokens.mjs (target check-tokens in the root project, … | tools/check-tokens.fixtures/ — layer-in-the-order-undefined (an o… |
req-token-scopedA theme for part of an app | enforced | apps/sandbox-e2e/src/theme.spec.ts, `apps/sandbox-e2e/src/a11y.spec… | see req-token-closure |
req-token-directiveThe [pctTheme] sugar directive | enforced | libs/components/theme/src/theme.spec.ts — the attribute written, fo… | `theme.spec.ts › "the directive and the raw attribute are the same th… |
req-token-systemThe theme follows the system until somebody says otherwise | enforced | apps/sandbox-e2e/src/preferences.spec.ts | `preferences.spec.ts › "with no dark preference :root stays light (th… |
req-token-skinThe skin is fully parameterised | enforced | libs/tokens/build.mjs — but only for the built-in skin | see req-token-contrast |
req-token-distributionThemes as ordinary CSS files | enforced | libs/components/check-package.mjs — points 1 and 2: the skin is in … | tools/check-package.fixtures/theme-missing/ — a package with no ski… |
req-token-densityThe density axis | enforced | tools/check-tokens.mjs (target check-tokens in the root project, … | tools/check-tokens.fixtures/ — four prepared inputs, each rejected … |
req-token-logicalStylesheets use logical properties only | enforced | tools/check-styles.mjs (target check-styles, in CI) — point 5: a … | tools/check-styles.fixtures/physical-padding/ (a property name) and… |
103 decisions
Why this way and what it costs — an ADR per irreversible choice, kept even when the plan that scheduled it is long gone.
- 0001Template and styles in separate filesread ↗
- 0002The skin ships in the packageread ↗
- 0003Wrapper and controlread ↗
- 0004Height stated outright, not derived from paddingread ↗
- 0005Signal forms without
ControlValueAccessorread ↗ - 0006The anchor and inheritance in an overlayread ↗
- 0007Configuration apart from textsread ↗
- 0008The motion axis in tokensread ↗
- 0009The number field on
type="text"read ↗ - 0010A generic value and
NoInferread ↗ - 0011Icons through a template and
PCT_ICONSread ↗ - 0012The transitive closure in a theme blockread ↗
- 0013No headless core / skin splitread ↗
- 0014Texts as a signal, read at render timeread ↗
- 0015MIT everywhere, rights to the entity, no CLAread ↗
- 0016Releasing under MIT is irreversible, so the order is a decisionread ↗
- 0017One home per fact: the concision criterion and its budgetread ↗
- 0018No Sass entry point: the token surface is custom properties and typesread ↗
- 0019A primitive colour is not the contract; a primitive scale isread ↗
- 0020The palette carries no spare stepsread ↗
- 0021An index is generated where every column is derivable, measured where one is notread ↗
- 0022One message line, and it is the error that takes itread ↗
- 0023A tolerance is for a measurement that wobblesread ↗
- 0024The overlay layer carries what an overlay severs, and borrows the closing stackread ↗
- 0025A panel says whether it takes focus, and the rest of the focus layer waits for a consumerread ↗
- 0026One channel per politeness, and a message with a home announces from itread ↗
- 0027A slot is a directive of its own, not a name in a stringread ↗
- 0028An icon set is a component, and an icon's box is the contractread ↗
- 0029A modal is an overlay, not a
<dialog>— the platform's modal is not composable with oursread ↗ - 0030A name is an attribute, a description is a referenceread ↗
- 0031A panel's tab order belongs to its triggerread ↗
- 0032A menu moves focus, a listbox points at itread ↗
- 0033An option is a row of data, not a component the consumer projectsread ↗
- 0034Multiplicity is a type, so it is a tagread ↗
- 0035A filter is a question, not a valueread ↗
- 0036A clear takes back what the trigger showsread ↗
- 0037Loading is a fact about the list, and a cursor names an optionread ↗
- 0038A window is measured, and its spacer is not an elementread ↗
- 0039A state the platform publishes is not ours to writeread ↗
- 0040A lockfile is repository material, the tree it locks is notread ↗
- 0041A height the platform computes, and a measurement only where it does notread ↗
- 0042A slider is the platform's range, and only the value it cannot pronounce is oursread ↗
- 0043A day is not an instant, and the field that takes one is text the application formatsread ↗
- 0044A toast is a change in a region that was already there, and its place is the top layerread ↗
- 0045A panel nobody chose is still text in the documentread ↗
- 0046A disclosure is the platform's, and so is the group it belongs toread ↗
- 0047A drawer is a region of the page, not a layer over itread ↗
- 0048A pagination owns its page number, and the folding is the only thing it computesread ↗
- 0049A progress bar is the platform's element under our own paintread ↗
- 0050A skeleton is a picture of a wait, and the wait belongs to the regionread ↗
- 0051Chips are a list the user shortens, and focus outlives the button it stood onread ↗
- 0052An avatar is a picture beside a name, and never the name itselfread ↗
- 0053A badge is a word wearing a tone, and the tone never speaks aloneread ↗
- 0054A breadcrumb is the way here, told in the platform's own linksread ↗
- 0055A stepper is a map of a journey the application steersread ↗
- 0056A tree is a walk the platform does not haveread ↗
- 0057Layout is three entrypoints, not a frameworkread ↗
- 0058The hero face is paint, and a gradient is three contrast checksread ↗
- 0059A theme is an attribute the skin reads, and the directive only spells itread ↗
- 0060The site is static by construction, and the shell is the library's first pageread ↗
- 0061The landing speaks in measurements, and says "machine-audited" until the ACRread ↗
- 0062The pages render a form, not markdown, and a demo file is its own code tabread ↗
- 0063The theme names its scheme to the platformread ↗
- 0064A face the consumer cannot reach without undoing ours is a variantread ↗
- 0065A treatment that paints is a component, because a directive cannotread ↗
- 0066A panel is a layer or a region, and the consumer says whichread ↗
- 0067A disc is a shape, because a radius does not draw oneread ↗
- 0068A harness is a declaration over the parts contractread ↗
- 0069A message about the list is not an item in itread ↗
- 0070What the control knows and the form cannot is a second channelread ↗
- 0071A link in button's clothes is a linkread ↗
- 0072A region key is the consumer's to installread ↗
- 0073The stop a long wait needs is the page's to throwread ↗
- 0074Density is a scope that re-points metrics, not an input a component readsread ↗
- 0075The push and the premiere are two moments, and only the second has an audienceread ↗
- 0076A tone is two channels and four names, settled onceread ↗
- 0077A number about the run is not a number about the coderead ↗
- 0078The site has an address, and it deploys behind a green CIread ↗
- 0079The first release is a measurement, and the history staysread ↗
- 0080An API is dated
nextuntil the release names itread ↗ - 0081A shard is a machine, not a second workerread ↗
- 0082A tone on a button is a face, and the label is what speaksread ↗
- 0083An icon source answers a name with data, and the box renders itread ↗
- 0084A fallback stays while Angular supports an engine without the feature, and e2e forces itread ↗
- 0085An icon-only button is a face, and its name is written on itread ↗
- 0086A time of day is a wall clock, and the field that takes one is text the application formatsread ↗
- 0087A warning is a verdict without a veto, and it is metadata the form does not graderead ↗
- 0088A row is measured by its own run, and the whole is measured at nightread ↗
- 0089One value, more than one control, and the consumer chooses whichread ↗
- 0090A day with a time is a wall clock with a date, and the field that takes one is two texts under one labelread ↗
- 0091The ring's runway is the cycle three times in the tree, because a mandatory snap refuses a windowread ↗
- 0092A control's reset takes back what the form cannot see, and the value stays the form'sread ↗
- 0093A bound of the field's own type reaches it through the platform's limit key, and the module ships the ruleread ↗
- 0094The release reaches
mainas a pull request, and the tag follows the mergeread ↗ - 0095Every component is released under MIT, and the order is what a consumer needsread ↗
- 0096A table is the consumer's markup or the library's rows, and the first is dressed element by elementread ↗
- 0097A data table is a typed engine under the first layer, and it grows into a grid by directivesread ↗
- 0098A table's window is opt-in, and the rows it skips are two rows the body draws without elementsread ↗
- 0099A chart is scales the marks share, a mark is a slot, and a ready chart is a reciperead ↗
- 0100A chart draws in layers, and its data are decimated to the pixelread ↗
- 0101The window, the cursor and the selection are the application's modelsread ↗
- 0102A series owns its colour, and the colour is never its only channelread ↗
- 0103A chart is a named picture, and its cursor is the platform's rangeread ↗
257 lessons
What building this taught us, one entry per surprise — the builder's diary, published because an audit reads character from how mistakes are handled.
- 1Angular does not support the NX "TS-solution" layoutread ↗
- 2Test discovery globs from
projectSourceRootread ↗ - 3Test target:
vite:testfor apps,testfor the libraryread ↗ - 4The token build is a transform of our own, not Style Dictionaryread ↗
- 5A coverage threshold needs
coverageIncluderead ↗ - 6The contrast guard let through a
disabledstate made withopacityread ↗ - 7Zoneless is declared explicitlyread ↗
- 8
zone.jsremoved from the dependencies entirelyread ↗ - 9
ControlValueAccessorturned out to be unnecessaryread ↗ - 10The contrast gate took in non-text pairs (SC 1.4.11)read ↗
- 11The Angular CLI MCP gives version-matched guidanceread ↗
- 12
FormCheckboxControlrequireschecked, notvalueread ↗ - 13
getComputedStylefrom a preview panel can be staleread ↗ - 14Formal conformance does not mean good qualityread ↗
- 15A part-name collision only surfaced in e2eread ↗
- 16Options in a group are projected content, not
viewChildrenread ↗ - 17The scoped theme was broken at the component tierread ↗
- 18An overlay panel renders outside the host treeread ↗
- 19
CSS.escapedoes not exist in jsdomread ↗ - 20On a native element
DefaultValueAccessorleadsread ↗ - 21The same message logic in four controlsread ↗
- 22The frame's padding created a dead zoneread ↗
- 23
page.mouse.click()does not scroll the pageread ↗ - 24The part-name collision repeated itself with the wrapperread ↗
- 25A wrapped select had a 19.6 px touch targetread ↗
- 26
FormFieldsupplies anNgControlitselfread ↗ - 27Patching the symptom left a dead zone visible in the cursorread ↗
- 28jsdom does not parse
:has()with a relative combinatorread ↗ - 29A height computed from padding cannot be lined upread ↗
- 30A test can click server HTML before hydrationread ↗
- 31The id generator was unsafe under SSRread ↗
- 32A number field step computed from the DOM dropped keypressesread ↗
- 33The states view found a disallowed ARIA attributeread ↗
- 34The stylesheet guessed intent from a slot's contentread ↗
- 35The control handed the wrapper its frame but not its panelread ↗
- 36The package carried no skin while the pipeline shone greenread ↗
- 37A generic in a component does not mean the template checks itread ↗
- 38Playwright's idiomatic emulation silently does nothingread ↗
- 39A visual test can be born dead in two waysread ↗
- 40A state carried by background alone disappears in high contrastread ↗
- 41The tool had a "before" hook where a "after" one was neededread ↗
- 42The e2e project had never been typecheckedread ↗
- 43Reading a non-existent token gives an empty stringread ↗
- 44
.nxignoredoes not disable a project, it removes a file from countingread ↗ - 45Removing a test raised coverageread ↗
- 46A partial declaration omits defaults, so OnPush can only be measured after linkingread ↗
- 47An inferred target is somebody else's decision about scope and looks exactly like your ownread ↗
- 48Two measurements guarding each other have to be INDEPENDENT, or they go dark togetherread ↗
- 49A snapshot does not close a promise about names, it freezes itread ↗
- 50A negative control proves a gate FIRES, not that it tells the truthread ↗
- 51A default a tool writes in cannot be removed, so a gate on its absence has no way to fireread ↗
- 52A pair nobody put in the policy is a pair the gate has no opinion aboutread ↗
- 53The visual gate has two budgets and only one was measuredread ↗
- 54An input's default value is a read at construction, even though the input is a signalread ↗
- 55A file that is in the package and a file that can be loaded are two different measurementsread ↗
- 56A media query fires even in an engine that cannot do what it asks aboutread ↗
- 57Coverage measures execution, not checking: 96.62% of lines is 63.54% of mutantsread ↗
- 58A gate that can fire and a gate that will fire are two different states — Stryker starts in the secondread ↗
- 59A task flaky under
nx affectedpoints at a shared directory, not at a time limitread ↗ - 60A scan is only as wide as its word list, and a hand-written list is narrower than its author thinksread ↗
- 61A copy carries its citations with it, so "is this file mentioned?" cannot see a dead treeread ↗
- 62A condition in a template is measured by nobodyread ↗
- 63A gate whose input is not a file cannot be cached, and a cached one answers from before the changeread ↗
- 64The published manifest is not the manifest anybody wroteread ↗
- 65An audit of the rendered page measures the pages you wrote, not the component you shippedread ↗
- 66When the only witness of a defect is somebody else's diagnostic, the cheap fix silences itread ↗
- 67A comment in a template is shipped; a comment in TypeScript is notread ↗
- 68A warning about a second one needs to be told when the first one leftread ↗
- 69A rule that fires on the way to something else is not the rule you think you haveread ↗
- 70A media query adds no specificity, and the browser it is written for hides thatread ↗
- 71Four coverage metrics, and each was blind to what another one caughtread ↗
- 72A content query sees the option before its inputs are boundread ↗
- 73A partially compiled package is not what an application carriesread ↗
- 74The obvious denominator for "used" would have deleted a live axisread ↗
- 75Eleven of twenty rows were wrong in the list a hand had just fixedread ↗
- 76Both modes were tested; that the two disagree belonged to neither testread ↗
- 77Two dictionaries, and the word that belongs to neitherread ↗
- 78A threshold decides two things and is argued about oneread ↗
- 79The message that names what moved is the message that stopped comparing the fileread ↗
- 80A shape may be named to see a class, never to stop seeing oneread ↗
- 81A gate reading modules cannot answer a question about bytesread ↗
- 82The wider event is not the safer guardread ↗
- 83The hiding was in a stylesheet nobody shipsread ↗
- 84A template's name and a template's context are two different checks, and no one shape gives bothread ↗
- 85A registry of markup is a registry of components, and a name in a string is checked when the string is a valueread ↗
- 86A shared kernel is where a cost stops being visibleread ↗
- 87The dependency a library can require without depending on itread ↗
- 88A gate's order is the repair it advisesread ↗
- 89The platform's modal is not composable with the library's overlaysread ↗
- 90What a modal must NOT silenceread ↗
- 91The name of a control is often in another elementread ↗
- 92A name that comes and goes is not a nameread ↗
- 93The outside press and the trigger's press are one eventread ↗
- 94An effect that reads what it writes: one consumer pays a pass, two never finishread ↗
- 95A host listener cannot stop a listener the template registered firstread ↗
- 96Projected content keeps the encapsulation of the template that declared itread ↗
- 97Two elements of one template are two instantiations, and neither is evidence about the otherread ↗
- 98Projected rows belong to the consumer's view, so the panel never owns how many existread ↗
- 99A two-way binding is checked in the read direction onlyread ↗
- 100A base class hides half a component from every gate that reads one class bodyread ↗
- 101Whether an accent is a letter is a question of language, and the trick that pretends otherwise folds half the alphabetread ↗
- 102An exception outlives the reason it names, and reads as a limit of the environmentread ↗
- 103A template reference inside a control-flow block cannot be seen from outside itread ↗
- 104A
<button>inside a<button>is two buttons, and only the parser says soread ↗ - 105A positioning context is a paint layer, and the text inside one loses its subpixel antialiasingread ↗
- 106An empty listbox is a critical violation, and
aria-busyis the specification's way of saying "not yet"read ↗ - 107A cursor kept as a number survives only a list that changes on a keystrokeread ↗
- 108
offsetHeightis an integer, and a list is arithmetic over a fractionread ↗ - 109Two repairs in one run, and the count of red cases cannot say which one workedread ↗
- 110An effect that follows the cursor must be woken by the cursor aloneread ↗
- 111Two engines lay out on two grids, so a measured value is compared with a tolerance and never roundedread ↗
- 112An ARIA attribute over a native state is written by us and read by nobodyread ↗
- 113A finding written down is an input to the gate that found itread ↗
- 114
NgControl.valueChangesisnullfor the whole of a sibling directive's constructorread ↗ - 115Build the optional part of a fallback last, or its absence takes the rest with itread ↗
- 116An element screenshot's height depends on where the element startsread ↗
- 117The forms interop writes
nullinto a model typednumber, and nothing says soread ↗ - 118
getComputedStyle(el, '::before')answers for an element that renders no::beforeread ↗ - 119Forced-colors mode is a request, and each engine honours a different part of itread ↗
- 120A fallback checked against the platform it falls back FROM is checked against nothingread ↗
- 121A control that vanishes on a timer takes the user's place on the page with itread ↗
- 122A
z-indexcannot get above the top layer, and the number that says it can is the dependency'sread ↗ - 123An ignored mutant is still instrumented, and a static attribute is where that showsread ↗
- 124A required input read from a sibling's host binding throws, and
@foris where that happensread ↗ - 125The testing tool's accessibility tree is not the browser'sread ↗
- 126
overflow: automakes an element focusable in two engines of threeread ↗ - 127A heading inside a
<summary>survives, because a<summary>is not a buttonread ↗ - 128
preventDefault()is the only way to refuse a disclosure, and it takes the keyboard with itread ↗ - 129A page the browser is not rendering has a frozen clock, and every transition on it reads as brokenread ↗
- 130A state attribute lands when the motion starts, not when it endsread ↗
- 131A clamp swallows the change it was written to correctread ↗
- 132An apostrophe in a comment is a quote to a scanner, and the gate then names an innocent fileread ↗
- 133A switch that turns a drawing off turns a behaviour off with it, and the three engines disagree about what is leftread ↗
- 134Forced colours keep a background colour and drop a gradient, so what a state is painted WITH decides whether it survivesread ↗
- 135A spy on an already-spied method is the same spy, so a per-case spy without a restore is one spy for the fileread ↗
- 136A placeholder measured in
1lhholds exactly the space the text will take, and one measured in pixels holds a guessread ↗ - 137
overflow: hiddentakes focus in no engine, whereoverflow: autotakes it in two of threeread ↗ - 138An empty
listpasses the audit that fails an emptylistbox, so the machinery has to be sized to the exact roleread ↗ - 139WCAG 2.5.8's inline exception ends where the sentence does, and axe measures the bar you thought was typographyread ↗
- 140A
listitemcomputes no name from its contents, so what a reader "hears" is measured as content, not as accessible nameread ↗ - 141Playwright's visibility is not the platform's
checkVisibility(), andcontent-visibilityis where they partread ↗ - 142A bare file name reaches a file only while the name is unique, and the first copied app tree ends thatread ↗
- 143A scoped formatter on a clean tree formats nothing, and a green battery says nothing about itread ↗
- 144A box that overhangs a scroll container by one pixel is a scrollbarread ↗
- 145A container query answers for an ancestor, never for the element that asksread ↗
- 146Inline-size containment makes a box's intrinsic width zero, and a column in a parent sized by its content collapses to its gutterread ↗
- 147A part-dressing rule scoped by the shared part name leaks onto every projected component that parts the same nameread ↗
- 148A component's token overrides, set on a host that contains a projected instance of the same component, inherit into itread ↗
- 149Two equal readings are not stillness: a scroll comes to rest in frames, not in round tripsread ↗
- 150
content-visibility: hiddenhides the contents; the box, and its padding, stayread ↗ - 151Encapsulation scopes a selector to a COMPONENT, not to an instance: a component that can hold itself must reach its parts by structureread ↗
- 152A click returns before the panel it opened has taken focus, and the key pressed on that round trip goes to the openerread ↗
- 153A key pressed where the handler cannot hear it proves the opposite of what the case claims: the drawer's
closeOnEscape=falseread ↗ - 154A generated file the hasher cannot see is a build that goes stale without ever going redread ↗
- 155A screenshot freezes the animation, not the class that starts itread ↗
- 156A
-webkit-shorthand is an alias, and an alias undoes the longhand above itread ↗ - 157Emulated encapsulation rewrites the selector, so it rewrites the specificityread ↗
- 158A box painted over a transparent control is the box the pointer lands onread ↗
- 159The router scrolls to an anchor by arithmetic, and reads no CSS while doing itread ↗
- 160A demo whose content has no width of its own has no width in a centred stageread ↗
- 161A signal written after the first render is a second render for everybody, and so is a view attached thenread ↗
- 162A rule on the inputs of an imprecise read is the workaround written downread ↗
- 163A platform rule written from memory is a claim, and the platform's own answer is the detectorread ↗
- 164A flake's record names the line the stack names, not the line the story ends onread ↗
- 165A blanked element is still a layer, and taking the layer away moved four pictures in another columnread ↗
- 166A host listener cannot get in front of the consumer's own, and a disabled link needs it toread ↗
- 167A drifting gradient's travel is its size written twice, and one frozen picture cannot see the differenceread ↗
- 168A reader keyed on the property name cannot see the colour inside a valueread ↗
- 169A comment is input, and one repository can need it read both waysread ↗
- 170An interface whose members are all optional proves nothing, and
implementslooks like proofread ↗ - 171A string equal to a selector is not a component, and a probe that skips the linker measures the wrong packageread ↗
- 172Half a cache is not half a speed-up: one half restores nothing, the other restores a green with no artifactread ↗
- 173
providerson a component pin it into its entrypoint, and a consumer who never named it pays for it wholeread ↗ - 174Twelve mechanisms taken out one at a time: what a suite holds is not what its case names sayread ↗
- 175The four criteria nobody measured: three defects, and two of them belonged to the harnessread ↗
- 176The template that has no parent: a report that had to stop asking DIread ↗
- 177Eleven floors, and every one of them measured for the first timeread ↗
- 178Motion that ends, and the order of three ways to stop itread ↗
- 179Thirty-five bytes with three suspects, all three refutedread ↗
- 180Four names at once, and the gate that could not see inside a switchread ↗
- 181A key nobody may install, and the hole in the honest defaultread ↗
- 182A gate that cannot start is a gate nobody hears stopread ↗
- 183A pause is true before it is visible, and webkit reports it in that orderread ↗
- 184The server under the suite is a client of the page, and it can navigate itread ↗
- 185A day's string is not fixed-width, and two functions had assumed it wasread ↗
- 186A sweep's seed belongs to the mutation snapshot, and its shrink is a leadread ↗
- 187Nine green properties, four mutants aliveread ↗
- 188The battery is a habit, not a list, and what it omits goes red in silenceread ↗
- 189A plan item can be stale in the direction of DONEread ↗
- 190"Enabled somewhere" is not a placement ruleread ↗
- 191The backstop named in the rules has not run in 144 commitsread ↗
- 192A measurement taken once became a constant, and the constant was the flakeread ↗
- 193A gate's reader is shared, so its blind spot is every point'sread ↗
- 194A denominator counted in the unit the code declares is not the unit the promise is aboutread ↗
- 195Determinism is not a statement about a generatorread ↗
- 196A list that decides what a gate looks at is a denominator nobody measuresread ↗
- 197A closed drawer is not an empty oneread ↗
- 198A case that asserts on the grid the real clock draws is a bomb with a date on itread ↗
- 199Proving a mutant equivalent by hand means compiling it, and a kill can still be reported as a survivorread ↗
- 200The mutation run's worker count is a fact about this machine, and it stands in no fileread ↗
- 201Which mutant the clock is holding says whether the wobble is a timing defect or a missing assertionread ↗
- 202There is a family of cases that fails only under the suite, and it is a shape, not a componentread ↗
- 203An accepted sketch is transferred, not interpreted, and the suite cannot tell the differenceread ↗
- 204A property sweep's gain can be invisible to the mutation scoreread ↗
- 205A survivor is a span, not a line: three mutants shared a start column and only one of them livedread ↗
- 206A dry run three seconds under its ceiling is a gate whose verdict the machine decidesread ↗
- 207A case built on the live input has to pin both sides of what it comparesread ↗
- 208A screen reader driven headlessly stands between you and the keyboardread ↗
- 209Three hypotheses about a flaky instrument, and all three were wrongread ↗
- 210The guard fired correctly and handed over a false causeread ↗
- 211When the symptom alternates, vary the count, not the magnituderead ↗
- 212A file name can make a repository un-clonable, and only a machine you do not own will say soread ↗
- 213A keystroke the instrument did not make is one it cannot reportread ↗
- 214Two jobs of one run gave two verdicts on the same four casesread ↗
- 215Uniting two walks made an absent field present, and
??reads absenceread ↗ - 216The register counted one spelling of a row, and the criterion counted a fourthread ↗
- 217Focus moved in the keypress; the tab ORDER moved one render laterread ↗
- 218The template argued what a reader hears, and no reader agreedread ↗
- 219The reader was asked what it had said, and answered with its bufferread ↗
- 220The release commit carried the changelog and nothing elseread ↗
- 221The report changed, and two cache keys did not noticeread ↗
- 222Nine green ticks, and nx had said nothingread ↗
- 223The consumer gate published to a registry that knew the public oneread ↗
- 224The window had focus and did not know itread ↗
- 225The link was there, and the pointer could not reach itread ↗
- 226The gate had not read the file, because git had notread ↗
- 227The shell held the stage, and the desktop never showed itread ↗
- 228The pipe dropped the verdictread ↗
- 229The gate's judge had a control; its readers had noneread ↗
- 230A target passed because the directory happened to be thereread ↗
- 231Four silent minutes, and two readings of themread ↗
- 232The ceiling named the moment, and the case it named was innocentread ↗
- 233Twice a superlative was put on a population that had been narrowedread ↗
- 234A shorthand is a reset, and it reached over a face that had drawnread ↗
- 235The absence had a reason, and the gate's comment had guessed itread ↗
- 236Six defects, one cause: the scan was a second lexerread ↗
- 237A guard is invisible to every case that carries what it filtersread ↗
- 238A false measurement is worse than none, because it closes the questionread ↗
- 239A measurement nobody looked at the machine for is a measurement of the machineread ↗
- 240One cache for every worktree, and a report that names its ownread ↗
- 241A repair made to one case of a file, and the file kept its other copiesread ↗
- 242The rehearsal was held to a stamp it cannot makeread ↗
- 243The release commit moved the manifest, and the rendering that embeds it stood stillread ↗
- 244The table cited a spec by the component's name, and nothing ever opened the specread ↗
- 245The key followed the window, and two readings had blamed the keyread ↗
- 246The rule saw a shape and the repair a cause, and neither walked the causeread ↗
- 247The index was the input, and the hash was the tree'sread ↗
- 248A component in a barrel is paid for by every importer, measured a second timeread ↗
- 249A centred stage that shrink-wraps its demo moves the control the reader just pressedread ↗
- 250A static mutant is priced by the tests it runs, not by its countread ↗
- 251A narrow run measures a file as the full one does, and the desk paid for the wholeread ↗
- 252A mutant that stops a module from loading is recorded as a survivor that ran nothingread ↗
- 253A factory call at the top of the shared chunk is paid by every entrypoint, until it is marked pureread ↗
- 254A spec file that fails outside its tests is one failed test, under either runnerread ↗
- 255A cache step that repeats the tool's default path keeps saving it after the tool movesread ↗
- 256Two hooks that place focus in one render: the later one wins, and a unit suite renders between keysread ↗
- 257Making a name unique among decorated classes does not make it mean one classread ↗