Tools
Change impact
What a change to a component library breaks, which components it reaches and by what path, and which examples check it, from the files two builds publish.
How it works
oddkin-impact (in @oddkin/analyzer) takes a snapshot of each revision’s built packages: the Custom Elements Manifest, oddkin.metadata.json, the package exports, and a hash of each module they name. It reads these files and runs none of the code. Each change between two snapshots is classified:
- Incompatible: a removed component, property, attribute, event, method, slot, part, CSS property, custom state, registration, export, or token; a token whose type or unit changed; a property whose values narrowed.
- Review: any other change to a contract, such as a token value, a template, a style, or a widened type. A person decides.
- Informational: an addition, or a change to descriptions only.
From each change it follows the dependencies (a style that reads a token, a definition that uses a style, a component built with another) to the components it affects. Their examples are the checks it selects, each with the path that selected it. A check passes only when every run of it passed; a check that did not run is never shown as passing.
# A snapshot of each revision's built package directories
npx oddkin-impact snapshot <package-dir>... --out base.json
npx oddkin-impact snapshot <package-dir>... --out head.json
# The changes, the affected components, and the selected checks
npx oddkin-impact compare base.json head.json --markdown report.md --json report.json--theme and --inspection add a theme’s tokens to a snapshot. --results merges the results of the checks you ran, and compare then exits with 1 when one failed. Everything runs locally: there is no hosted service, and nothing is published.
A recorded change
In this repository, scripts/impact-demo.mjs makes a real change and reports on it. In a temporary worktree it commits two edits on a base commit (the menu’s item part becomes menuitem, and the default theme’s specimen surface gets lighter), builds both revisions with their own build steps, compares them, and runs the selected checks on the head’s build in three browsers. This page is generated from the run recorded in docs/impact-demo.
Base: 35b6dcd2e327. Head: the base and 2 commits:
| Commit | Subject | Files |
|---|---|---|
d74d1f391f9c | Menu: name the item part after its role, menuitem | packages/components/src/menu/menu.template.ts, packages/components/src/menu/menu.ts |
749a34f00b91 | Theme: a lighter specimen surface | packages/tokens/themes/default.theme.json |
6 changes: 1 incompatible, 4 review, 1 informational. 4 components affected, with no coverage gaps. 29 checks selected: 29 passed, in Chromium, Firefox, and WebKit.
What changed
Renaming the part breaks a consumer’s odd-menu::part(item) rule, and no test notices. Items are matched by id, so without a migration record a rename is a removal and an addition: the report notes the likely rename, as the two parts have the same contract, and still counts the removal.
| Item | Classification | Change | Reason |
|---|---|---|---|
part:odd-menu#item | incompatible | removed | removed; possible rename to part:odd-menu#menuitem (unconfirmed) |
class:odd-menu | review | changed | class changed |
template:@oddkin/components/dist/menu/menu.template.js#menuTemplate | review | changed | template changed |
theme:base | review | changed | theme changed |
token:color.surface.specimen | review | changed | value or definition changed |
part:odd-menu#menuitem | informational | added | added |
What it affects
Each path runs from a changed item to the component it reaches.
| Component | Path |
|---|---|
odd-combobox | token:color.surface.specimen → style:@oddkin/components/dist/combobox/combobox.styles.js#comboboxStyles → definition:odd-combobox → component:odd-combobox |
odd-menu | class:odd-menu → component:odd-menu |
odd-picker | token:color.surface.specimen → style:@oddkin/components/dist/combobox/combobox.styles.js#comboboxStyles → definition:odd-picker → component:odd-picker |
odd-split-button | class:odd-menu → component:odd-menu → definition:odd-split-button → component:odd-split-button |
What checks it
The examples of the affected components, run on the head’s build. The report lists each check with its path.
| Component | Examples | Result |
|---|---|---|
odd-combobox | children, default, disabled, grouped, inForm, loading, multiple, readonly, selectAll, serverFiltered, views | 11 passed in Chromium, Firefox, and WebKit |
odd-menu | contextMenu, default, disabled, fromData, glyphOnly | 5 passed in Chromium, Firefox, and WebKit |
odd-picker | default, disabled, empty, inForm, list, listMultiple, loading, multiple | 8 passed in Chromium, Firefox, and WebKit |
odd-split-button | default, disabled, fromData, loading, secondary | 5 passed in Chromium, Firefox, and WebKit |
Every selected check passed, and the report still marks part:odd-menu#item incompatible: passing checks do not make a contract change compatible.
What agents read
The agent kits of both revisions, packaged with the same oddkin-kit, differ where the change does, so an agent that reads the head’s kit finds the new part and the new value. Each kit.json holds a fingerprint of the kit’s inputs (inputs) and the hash of the metadata it was written from (sha256), so a kit that no longer matches its package is detectable.
| File | Change |
|---|---|
ai/kit.json | inputs changed |
ai/references/tokens/semantic.md | color.surface.specimen: light: #efedfc; dark: #29263d → light: #f3f1fd; dark: #29263d |
components/kit.json | inputs and sha256 changed |
components/references/components/odd-menu.md | item → menuitem |
components/references/tokens/semantic.md | color.surface.specimen: light: #efedfc; dark: #29263d → light: #f3f1fd; dark: #29263d |
Reproduce it
In a checkout of the repository:
npm install
npm run build
node scripts/impact-demo.mjs --base 35b6dcd2e327 --runThe files go to .oddkin/impact/demo; --record <dir> copies the ones recorded here. The script exits with 1 when a selected check fails.
The evidence
What the site’s claims rest on, where each is kept:
CI in three browsers
Each push to main and each pull request: lint, type checks, the build, the unit tests, the browser and end-to-end tests in Chromium, Firefox, and WebKit, the packed packages, and a change-impact report against its base in the job summary.
Fresh installs
New Vite, React, Vue, Svelte, and Angular projects install the packed packages and their own build tools, type-check when they use TypeScript, and are tested from their production builds. Each week, the same tests install the published packages from npm.
Change-impact analysis
How snapshots, classifications, dependency paths, and check states work, and what is not built yet.
Architecture decisions
Every decision record, with its area and status, as the records give them.
The recorded run
The patch, the report in Markdown and JSON, and the kit diff this page is generated from.
Limits
- The snapshot and report formats are not frozen: they can change in a minor release (ADR 0047).
- A path is only as complete as its inputs. A module whose source was not supplied, a package that was not read, or a dynamic definition is listed as a coverage gap, and widens the selection to every example of its package.
- Visual differences and component-family mappings are not compared yet.
- A library described only by a standard Custom Elements Manifest gets its changes and affected components; it gets checks where it publishes examples (libraries not built with Oddkin).