# How `self_check.py` Validates Diagram HTML Output: A Complete Technical Breakdown

> Explore how self_check.py validates diagram HTML output. This script ensures security, SVG accessibility, and motion control compliance in the cathrynlavery/diagram-design repository.

- Repository: [Cathryn Lavery/diagram-design](https://github.com/cathrynlavery/diagram-design)
- Tags: internals
- Published: 2026-09-11

---

**The [`self_check.py`](https://github.com/cathrynlavery/diagram-design/blob/main/self_check.py) script in the `cathrynlavery/diagram-design` repository implements a deterministic, dependency-free validation pipeline that inspects generated HTML files for security vulnerabilities, SVG accessibility compliance, and motion control contract adherence.**

The `diagram-design` repository provides a framework for generating accessible, animated diagrams. The [`self_check.py`](https://github.com/cathrynlavery/diagram-design/blob/main/self_check.py) validator, located at [`skills/diagram-design/scripts/self_check.py`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/scripts/self_check.py), serves as the gatekeeper to ensure every output file meets strict safety and semantic standards without requiring external dependencies.

## HTML Parsing and Data Collection

The validation process begins with the **`DiagramParser`** class, a specialized subclass of Python's standard `HTMLParser`. This parser incrementally scans the markup to collect potential violations and metadata before any rule enforcement begins.

### Extracting Unsafe Elements and Attributes

As `DiagramParser` walks the document tree in the `verify()` function, it captures several categories of content into discrete collections:

- **Unsafe tags** such as `<base>`, `<embed>`, and `<object>` that could introduce security risks
- **Executable attributes** matching the `on*` pattern (e.g., `onclick`, `onload`) that could execute arbitrary JavaScript
- **External references** extracted from `src`, `href`, and similar attributes for subsequent validation
- **CSS fragments** found in inline `style` attributes and `<style>` blocks for later analysis
- **SVG metadata** including `role`, `<title>`, `<desc>`, and `aria-labelledby` relationships
- **Motion markup** via `data-motion-*` attributes to identify animated diagrams
- **Script blocks** to enforce single-script limitations

## Security and Resource Validation

### CSS Reference Sanitization with check_css_references()

The `check_css_references()` function normalizes CSS escape sequences before applying security policies. According to the source code implementation, it specifically rejects:

- **`@import`** rules that could load external stylesheets dynamically
- **`url()`** functions pointing to non-fragment targets (remote resources)
- **`image-set()`** declarations that could load unauthorized image sources
- Any remote URL that does not match the approved Google Fonts `/css2` endpoint pattern

### Generic Reference Verification

The `reference_error()` function validates every captured `src` and `href` attribute against a strict whitelist:

- Empty or fragment-only URLs (e.g., `#section`) are permitted for internal navigation
- `javascript:` URLs and `data:text/html` payloads are blocked immediately as XSS vectors
- Non-image data URIs are rejected to prevent code injection
- Remote URLs are restricted solely to the approved Google Fonts stylesheet for `<link rel="stylesheet">` elements

## SVG Accessibility and Semantic Requirements

### check_svgs() Implementation

The `check_svgs()` function enforces WCAG-compliant SVG structure through several concrete checks:

- The document must contain at least one SVG that is not hidden via `aria-hidden="true"`
- Every SVG must declare **`role="img"`** to expose it as an image to assistive technologies
- A non-empty `<title>` element must exist, followed immediately by a `<desc>` element to provide accessible names and descriptions
- The `aria-labelledby` attribute must correctly reference the IDs of the `<title>` and `<desc>` elements, and these IDs must be prefixed (not bare strings) to ensure uniqueness in the DOM

## Script and Motion Contract Enforcement

### Canonical Script Validation with check_scripts()

The `check_scripts()` function enforces strict limitations on JavaScript execution within diagram files:

- Only a single `<script>` element is permitted per document
- The script tag must be explicitly closed (not self-closing) to ensure proper parsing across browsers
- The element must carry exactly the canonical **`data-diagram-controls`** attribute
- The script body must byte-match the canonical motion controller stored in [`assets/template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/assets/template-motion.html)

### Motion Controls and Accessibility with check_motion()

When motion-related markup is detected in the parsed content, `check_motion()` validates complex animation contracts:

- Exactly one root element must declare **`data-motion-root`** with a supported **`data-motion-mode`** (such as `step` or `reveal`)
- Step counts must be ASCII decimal integers within the **0–8** range
- The item budget is capped at **12 elements** maximum
- Semantic steps must form a contiguous sequence without gaps (1, 2, 3, not 1, 3, 4)
- No more than two items may share the same step value
- Controlled modes require proper control buttons, action attributes, and a live status element
- CSS must include **`prefers-reduced-motion`** media queries and print media fallbacks
- A **`<noscript>`** explanation must be present for users with JavaScript disabled

## Command-Line Interface and CI Integration

The **`main()`** entry point parses file paths from command-line arguments and iterates over each target. For every file, it invokes `verify(path)`, which orchestrates the full validation pipeline and aggregates errors into a single list.

```bash

# Validate a single diagram file

python3 skills/diagram-design/scripts/self_check.py path/to/diagram.html

# Batch validation of multiple outputs

python3 skills/diagram-design/scripts/self_check.py diagram1.html diagram2.html diagram3.html

```

The script outputs **OK** for files passing all checks or **FAIL** followed by specific violation messages. This deterministic output makes it suitable for CI/CD integration as a pre-commit hook or build gate, aborting builds when contract violations are detected.

## Summary

- **[`self_check.py`](https://github.com/cathrynlavery/diagram-design/blob/main/self_check.py)** provides a zero-dependency validation solution for diagram HTML output in the `cathrynlavery/diagram-design` repository.
- **`DiagramParser`** incrementally extracts unsafe tags, executable attributes, and motion metadata using Python's standard `HTMLParser`.
- **`check_css_references()`** blocks dangerous CSS constructs like `@import` and restricts remote fonts to approved Google Fonts URLs only.
- **`check_svgs()`** enforces accessible SVG structure requiring `role="img"`, sequential `<title>` and `<desc>` elements, and valid `aria-labelledby` references.
- **`check_scripts()`** limits documents to a single canonical script that must match the template in [`assets/template-motion.html`](https://github.com/cathrynlavery/diagram-design/blob/main/assets/template-motion.html).
- **`check_motion()`** validates animation budgets (≤12 items), step contiguity (0–8), and accessibility fallbacks for reduced-motion preferences.

## Frequently Asked Questions

### What specific CSS patterns does self_check.py block?

According to the implementation in `check_css_references()`, the validator explicitly rejects `@import` rules, `url()` functions targeting non-fragment URLs, `image-set()` declarations, and any remote stylesheet that does not match the approved Google Fonts `/css2` endpoint pattern. It normalizes CSS escape sequences before performing these comparisons to prevent evasion attempts.

### How does the validator ensure SVG accessibility?

The `check_svgs()` function requires that SVGs declare `role="img"`, contain a non-empty `<title>` immediately followed by `<desc>`, and use prefixed (non-bare) IDs in `aria-labelledby` references. It also verifies that at least one SVG in the document is not hidden via `aria-hidden="true"`, ensuring screen readers can access the diagram content.

### Can self_check.py be used in automated CI pipelines?

Yes. The script accepts multiple file paths as command-line arguments and processes them sequentially without external dependencies. It exits with a **FAIL** status and descriptive error messages when violations are detected, making it suitable for pre-commit hooks or build automation where any non-OK output should abort the deployment process.

### What motion animation constraints does the validator enforce?

The `check_motion()` function validates that animations have exactly one root element with a supported `data-motion-mode`, step counts as ASCII decimals between 0–8, a maximum of 12 items, contiguous semantic steps without gaps, and no more than two items per step. It also requires proper accessibility fallbacks including `prefers-reduced-motion` media queries and `<noscript>` explanations for users with JavaScript disabled.