Appearance
13. Conformance Suite
13.1 Purpose
The conformance suite is a collection of machine-readable test vectors that verify implementations against the normative clauses of this specification. An implementation's conformance claim (§2.6) is validated by running the suite and reporting pass/fail per vector.
The suite is distributed as the @mdflow/spec-tests package, co-located with this specification in the MdFlow monorepo.
13.2 Vector format
Vectors are authored in a single source markdown file (vectors.md) using CommonMark-style fenced example blocks, and compiled to JSON for programmatic consumption. A vector has the following shape:
Vector {
id: string, // unique, stable across versions
section: string, // spec § reference, e.g. "10.3.1"
class: 'batch' | 'streaming' | 'both',
target: 'parser' | 'renderer' | 'full-stack' | 'extension',
source: string, // input MdFlow source
chunks?: string[], // for streaming vectors: split pattern
expected_html: string, // canonical HTML output
expected_ast?: Node, // optional AST assertion
expected_events?: Event[], // for event-only element vectors
tags: string[] // free-form e.g. "security", "xss", "table"
}The source-markdown representation looks like:
### 10.3.1.1 Evasion: percent-encoded javascript scheme
```mdflow
[click](java%73cript:alert(1))
```
```html
<p><a href="">click</a></p>
```Metadata (class, target, tags) lives in HTML comments above each block. The extractor produces vectors.json.
13.3 Sections
The suite is organized into sections mirroring the spec:
| Directory | Scope |
|---|---|
core/blocks/ | Block syntax vectors (§6) |
core/inlines/ | Inline syntax vectors (§7) |
core/html/ | Custom-element mechanics (§8) |
core/streaming/ | Streaming semantics (§5) |
core/errors/ | Error recovery (§11) |
security/ | Security model (§10) |
extensions/ | Per-extension vectors (each subdirectory = one extension) |
Each vector's id is <section>/<subsection>/<slug>, e.g., security/url-filter/javascript-scheme.
13.4 Security vectors
Every prohibition and filter in §10 MUST have at least one vector in the security/ subtree. The mandatory minimum coverage is:
| Rule | Section | Vector id prefix |
|---|---|---|
| P-1 (no innerHTML) | 10.2 | security/no-innerhtml/ |
| P-2 (no eval family) | 10.2 | security/no-eval/ |
| P-3 (no on* attrs) | 10.2 | security/no-event-handlers/ |
| P-4 (no script/style) | 10.2 | security/no-raw-html/ |
| P-5 (URL schemes) | 10.3.1 | security/url-filter/ |
| P-6 (style url/expression) | 10.2 | security/css-injection/ |
| P-7 (CSS custom props) | 10.2 | security/css-custom-props/ |
| P-8 (code opacity) | 10.2 | security/code-opacity/ |
Security vectors MUST include at least the XSS vectors from the OWASP XSS Filter Evasion Cheat Sheet that are applicable to markdown contexts.
13.5 Interactive vectors
Vectors under core/html/interactive/ verify §12.2 REQ-INT-1 through REQ-INT-3 by:
- Rendering source
A, capturing DOM state, then re-rendering sourceA'that differs only in surrounding text, and asserting the interactive element's identity preservation. - Asserting event-only elements emit events but produce no DOM.
13.6 Streaming vectors
Vectors under core/streaming/ specify a chunks array. The runner:
- Creates an
MdFlowinstance. - For each chunk, calls
push(chunk). - Calls
flush(). - Asserts the resulting canonical HTML matches
expected_html.
For each streaming vector, an additional test splits the source at every byte boundary and asserts chunk-boundary independence (§5.2). This generates O(|source|) additional assertions per streaming vector; the runner MAY sample boundaries for large sources.
13.7 Runner
A reference runner (@mdflow/spec-tests/src/runner/) implements:
runVector(vector: Vector, impl: MdFlowImpl): Resultwhere Result is { pass: boolean, actual?: string, diff?: string }. The runner is implementation-agnostic: any parser/renderer exposing a minimal adapter interface can be tested.
13.8 Extension vector contribution
Extensions MUST contribute their vectors under extensions/<extension-name>/. Each extension's vectors carry the target: 'extension' marker. Core conformance does NOT require extension vectors to pass; extension conformance requires both core + the extension's own vectors.
13.9 Coverage reporting
Implementations SHOULD publish their suite run output as a JSON file listing {id, pass, duration_ms} per vector. This enables cross- implementation comparison.
13.10 Minimum vector count for v1.0
The v1.0 suite targets (MUST) at least:
- 60 block-syntax vectors
- 80 inline-syntax vectors
- 40 custom-element vectors
- 40 streaming vectors
- 40 security vectors
- 20 error-recovery vectors
A total of at least 280 vectors in the core suite. Additional vectors MAY be added in patch releases without constituting a version bump of the spec itself, provided they do not invalidate prior conformance.
13.11 Vector stability
Once published with a vector ID, a vector's source, expected_html, and class MUST NOT change within a minor spec version. Errata MAY correct clearly-broken vectors; corrections are called out in the CHANGELOG (§16).
13.12 CommonMark vector compatibility
The suite MAY include CommonMark vectors as an INFORMATIVE subset under commonmark/ with tag commonmark-overlap. These are NOT part of MdFlow conformance; they exist to aid implementers claiming dual conformance.