Validating Unknown Section Headings in DESIGN.md for Consumer Behavior

The DESIGN.md linter implements a consumer behavior policy that preserves unknown section headings without raising errors, filtering them from order validation checks while appending them to the end of the document during auto-fix operations.

When working with the google-labs-code/design.md repository, understanding how the linter handles non-standard section headings is essential for maintaining flexible design system documentation. The consumer behavior specification explicitly defines that unknown section headings must be preserved rather than rejected, allowing teams to extend their documents while maintaining validation integrity. This article explains the complete implementation of this policy, from the specification requirements to the underlying code in the section-order rule.

Consumer Behavior Policy for Unknown Sections

The handling of unrecognized headings is governed by a strict consumer behavior policy defined in the project specification.

Specification Requirements

According to the consumer behavior table in README.md, the linter must follow a specific protocol for unknown content:

  • Unknown section heading: Preserve; do not error

This means the validator accepts any heading that does not match the canonical list, ensuring that custom sections like ## Iconography or ## Accessibility Guidelines remain intact in your documentation.

Implementation in the Section-Order Rule

The core logic resides in packages/cli/src/linter/linter/rules/section-order.ts. The rule implements a three-stage process:

  1. Parse the document to extract state.sections
  2. Resolve aliases using the resolveAlias function (defined in spec-config.js), which maps known aliases to canonical names while leaving unknown headings unchanged
  3. Filter the list to include only sections present in CANONICAL_ORDER (referenced as ORDER_MAP in the implementation)

Because unknown headings never appear in the canonical order map, they are automatically excluded from ordering validation.

The Validation Process for Unknown Headings

Understanding the exact flow helps you predict how the linter will treat your custom sections.

Step 1: Parsing and Alias Resolution

When the linter processes a DESIGN.md file, it first extracts all headings into an array. Each heading passes through resolveAlias:

// From spec-config.js
const resolved = resolveAlias(heading); // "Brand & Style" → "Brand"
// Unknown headings pass through unchanged: "Iconography" → "Iconography"

This resolution step ensures that recognized variations of standard sections are normalized, while custom sections remain untouched.

Step 2: Filtering and Order Checking

Before validating section sequencing, the rule filters out any unknown headings:

// In packages/cli/src/linter/linter/rules/section-order.ts
const knownSections = sections
  .map(resolveAlias)            // unknown headings stay as-is
  .filter(s => ORDER_MAP.has(s)); // drop anything not in the canonical list

If the filtered list is empty (for example, when a file contains only custom sections), the sectionOrder function returns an empty array of findings. This ensures that documents with exclusively unknown sections generate zero errors and zero warnings.

Practical Implementation Examples

Linting Files with Unknown Sections

When running the CLI linter against a file containing non-standard headings, the tool preserves the content without complaints:

npx @google/design.md lint examples/atmospheric-glass/DESIGN.md

If the file contains ## Iconography (which is not in the canonical list), the JSON output shows no errors for that heading:

{
  "findings": [
    // … other rule findings, but none about “Iconography”
  ],
  "summary": { "errors": 0, "warnings": 2, "info": 1 }
}

Programmatic Rule Usage

You can observe this behavior directly when using the rule programmatically:

import { sectionOrder } from '@google/design.md/cli/src/linter/linter/rules/section-order.js';
import type { DesignSystemState } from '@google/design.md/cli/src/linter/model/spec.js';

const state: DesignSystemState = {
  sections: ['Overview', 'Iconography', 'Colors'] // “Iconography” is unknown
};

const findings = sectionOrder(state);
console.log(findings); // → []

The function returns an empty array because Iconography is filtered out before the order check runs.

Auto-Fix Behavior

When you run designmd fix, the fixer handles unknown sections by appending them after the last known canonical section. This preserves your custom content while ensuring the document follows the standard structure for recognized sections:

// In packages/cli/src/linter/fixer/handler.ts (simplified logic)
if (!ORDER_MAP.has(resolved)) {
  // push unknown section to the end of the file
}

This behavior is explicitly verified in packages/cli/src/linter/fixer/handler.test.ts, ensuring that custom sections always migrate to the end of the document rather than being deleted or causing failures.

Testing and Verification

The consumer behavior policy is protected by comprehensive test coverage:

  • section-order.test.ts: Validates that the section-order rule ignores unknown sections when checking sequence
  • handler.test.ts: Confirms that the fixer appends unknown sections at the end of the file rather than inserting them arbitrarily

These tests ensure that the "preserve; do not error" policy remains consistent across linter updates.

Summary

  • The consumer behavior policy requires that unknown section headings be preserved without generating errors
  • The section-order rule filters unknown headings using ORDER_MAP.has() before performing sequence validation
  • Unknown sections are excluded from the knownSections array, resulting in empty findings for documents containing only custom headings
  • The auto-fixer appends unknown sections after the last canonical section, maintaining document validity while preserving user content
  • All behavior is verified in section-order.test.ts and handler.test.ts

Frequently Asked Questions

What happens if a DESIGN.md file contains only unknown section headings?

The linter returns an empty findings array with zero errors. Because the filtering logic removes all sections before the order check (since none exist in ORDER_MAP), the validation passes silently, preserving your custom document structure.

Does the linter suggest canonical alternatives for unknown headings?

No. The resolveAlias function only maps recognized aliases to their canonical equivalents (for example, converting "Brand & Style" to "Brand"). It does not perform fuzzy matching or suggest alternatives for headings that are completely unknown to the specification.

How does the fixer determine where to place unknown sections?

The fixer appends unknown sections immediately after the last recognized canonical section in the document. This is implemented in packages/cli/src/linter/fixer/handler.ts to ensure that standard sections maintain their proper order while custom content remains accessible at the end of the file.

Is the consumer behavior policy configurable?

No. The "preserve; do not error" behavior for unknown section headings is hardcoded according to the specification table in README.md. This ensures consistent behavior across all DESIGN.md consumers and prevents accidental data loss during linting operations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →