# How DESIGN.md Handles Unknown Section Headings and Custom Extension Keys

> DESIGN.md tolerates unknown headings and custom keys, preserving values and warning you. Ensure forward compatibility without failures.

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

---

**DESIGN.md gracefully tolerates unknown section headings and custom extension keys by preserving the original values while emitting linter warnings, ensuring forward compatibility without hard failures.**

The [`google-labs-code/design.md`](https://github.com/google-labs-code/design.md/blob/main/google-labs-code/design.md) parser and linter are architected for resilience, allowing documents to evolve with vendor-specific extensions or new sections. By implementing fallback mechanisms in the alias resolution and YAML parsing stages, the system handles unknown content without breaking the build.

## Resolving Unknown Section Headings

The parser normalizes section headings through the **`resolveAlias`** utility, which implements a fail-soft strategy for unrecognized values.

### Alias Resolution via resolveAlias

In [`packages/cli/src/linter/spec-config.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/spec-config.ts), the `resolveAlias` function checks headings against the `SECTION_ALIASES` mapping. When a heading does not match any known alias, the function returns the original string unchanged using the nullish coalescing operator:

```typescript
return SECTION_ALIASES[heading] ?? heading;

```

This behavior allows documents to contain non-standard section headings without triggering parsing errors. The section remains valid, though it is not mapped to a canonical specification name.

The following example demonstrates how known aliases resolve to canonical names while **unknown section headings** pass through unchanged:

```typescript
import { resolveAlias } from './spec-config';

// Known alias – resolves to its canonical name
console.log(resolveAlias('Brand & Style')); // → "Overview"

// Unknown heading – returned unchanged
console.log(resolveAlias('NonExistentSection')); // → "NonExistentSection"

```

### Section Order Validation

The **`section-order`** rule in [`section-order.ts`](https://github.com/google-labs-code/design.md/blob/main/section-order.ts) interprets the resolved heading name. Since unknown headings return their original input rather than a canonical alias, the rule recognizes them as "unknown" and skips ordering validation for those specific sections. This prevents the linter from enforcing canonical sequence constraints on custom or future sections.

The test suite verifies this behavior through the case `resolveAlias returns input for unknown heading`, confirming that the system preserves custom headings exactly as authored.

## Processing Custom Extension Keys

Beyond section headings, the system accommodates arbitrary top-level YAML keys through a dedicated collection mechanism.

### Capture in Model Handler

In [`packages/cli/src/linter/model/handler.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/model/handler.ts), the parser scans for keys that are not part of the core DESIGN.md specification. These **custom extension keys** are collected into the `unknownKeys` array, while their raw YAML values are stored in `unknownKeyValues`. This dual-storage approach allows downstream tooling to access extension data programmatically without interfering with standard spec generation.

```typescript
import { parseDesignSystem } from './parser/handler';

// Suppose the DESIGN.md document contains:
//
// customExtension:
//   foo: bar
//   baz: 42
//
const parsed = parseDesignSystem(rawYaml, sourceMap, sections, docSections);

// `parsed.unknownKeys` lists the extra top‑level keys
console.log(parsed.unknownKeys); // → ["customExtension"]

// Raw values for those keys are kept intact
console.log(parsed.unknownKeyValues.customExtension);
// → { foo: "bar", baz: 42 }

```

### Linting and Warnings

The linter surfaces these extensions through the **`unknownKey`** rule located in [`packages/cli/src/linter/linter/rules/unknown-key.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/linter/rules/unknown-key.ts). When `state.unknownKeys` contains entries, the rule emits a finding for each unrecognized key:

```typescript
import { lint } from './linter';

// The linter will emit a finding for each unknown top‑level key
const result = lint(parsedDesignSystem);
result.findings.forEach(f => console.log(f.message));
// Example output: "Unknown top‑level key: customExtension"

```

This warning mechanism alerts authors to potential typos or experimental extensions while preserving the document's validity for custom workflows.

## Key Implementation Files

The following source files implement the tolerance mechanisms for **unknown section headings** and **custom extension keys**:

| File | Role |
|------|------|
| [`packages/cli/src/linter/spec-config.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/spec-config.ts) | Defines `resolveAlias` and the canonical/alias mapping. |
| [`packages/cli/src/linter/linter/rules/unknown-key.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/linter/rules/unknown-key.ts) | Linter rule that flags unknown top-level keys. |
| [`packages/cli/src/linter/model/handler.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/model/handler.ts) | Parses the document, collects `unknownKeys` and `unknownKeyValues`. |

## Summary

- **DESIGN.md** handles **unknown section headings** by returning them unchanged from `resolveAlias`, allowing the `section-order` rule to skip validation for non-canonical sections.
- **Custom extension keys** are captured in `unknownKeys` and `unknownKeyValues` during parsing, preserving raw YAML without breaking spec generation.
- The **`unknownKey`** linter rule emits warnings for unrecognized top-level keys, maintaining visibility into extensions while ensuring forward compatibility.
- These mechanisms are implemented in [`spec-config.ts`](https://github.com/google-labs-code/design.md/blob/main/spec-config.ts), [`model/handler.ts`](https://github.com/google-labs-code/design.md/blob/main/model/handler.ts), and [`unknown-key.ts`](https://github.com/google-labs-code/design.md/blob/main/unknown-key.ts) respectively.

## Frequently Asked Questions

### What happens when DESIGN.md encounters an unknown section heading?

The `resolveAlias` function in [`packages/cli/src/linter/spec-config.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/spec-config.ts) returns the original heading string unchanged. The `section-order` rule then identifies it as unknown and bypasses canonical ordering checks, keeping the document valid.

### Can I use custom extension keys in DESIGN.md without breaking the parser?

Yes. The parser in [`packages/cli/src/linter/model/handler.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/model/handler.ts) collects custom top-level keys into `unknownKeys` and stores their values in `unknownKeyValues`. This allows arbitrary extensions to coexist with standard sections without causing parsing failures.

### How does the linter report unknown keys in DESIGN.md?

The **`unknownKey`** rule in [`packages/cli/src/linter/linter/rules/unknown-key.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/linter/rules/unknown-key.ts) checks `state.unknownKeys` and emits a finding for each unrecognized key, such as `"Unknown top-level key: customExtension"`, alerting authors while preserving the document.

### Where is the alias resolution logic implemented in DESIGN.md?

The alias resolution logic resides in [`packages/cli/src/linter/spec-config.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/spec-config.ts), which exports the `resolveAlias` function and maintains the `SECTION_ALIASES` mapping used to normalize canonical section names.