# Validating Unknown Section Headings in DESIGN.md for Consumer Behavior

> Learn how the DESIGN.md linter validates unknown section headings without errors, preserving them for consumer behavior analysis and auto-fixing document order.

- Repository: [Google Labs Code/design.md](https://github.com/google-labs-code/design.md)
- Tags: how-to-guide
- Published: 2026-06-29

---

**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`](https://github.com/google-labs-code/design.md/blob/main/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`](https://github.com/google-labs-code/design.md/blob/main/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`](https://github.com/google-labs-code/design.md/blob/main/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`](https://github.com/google-labs-code/design.md/blob/main/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`](https://github.com/google-labs-code/design.md/blob/main/DESIGN.md) file, it first extracts all headings into an array. Each heading passes through `resolveAlias`:

```ts
// 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:

```ts
// 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:

```bash
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:

```json
{
  "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:

```ts
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:

```ts
// 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`](https://github.com/google-labs-code/design.md/blob/main/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`](https://github.com/google-labs-code/design.md/blob/main/section-order.test.ts)**: Validates that the section-order rule ignores unknown sections when checking sequence
- **[`handler.test.ts`](https://github.com/google-labs-code/design.md/blob/main/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`](https://github.com/google-labs-code/design.md/blob/main/section-order.test.ts) and [`handler.test.ts`](https://github.com/google-labs-code/design.md/blob/main/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`](https://github.com/google-labs-code/design.md/blob/main/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`](https://github.com/google-labs-code/design.md/blob/main/README.md). This ensures consistent behavior across all DESIGN.md consumers and prevents accidental data loss during linting operations.