Skip to content

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:

DirectoryScope
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:

RuleSectionVector id prefix
P-1 (no innerHTML)10.2security/no-innerhtml/
P-2 (no eval family)10.2security/no-eval/
P-3 (no on* attrs)10.2security/no-event-handlers/
P-4 (no script/style)10.2security/no-raw-html/
P-5 (URL schemes)10.3.1security/url-filter/
P-6 (style url/expression)10.2security/css-injection/
P-7 (CSS custom props)10.2security/css-custom-props/
P-8 (code opacity)10.2security/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 source A' 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:

  1. Creates an MdFlow instance.
  2. For each chunk, calls push(chunk).
  3. Calls flush().
  4. 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): Result

where 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.