ODS · Validation & Tooling Contract
ODS lint rules, binary compliance contract, lifecycle phase separation, unknown-content behavior, diagnostic format, and tooling validation requirements.
ODS · Validation & Tooling Contract
This document specifies the Normative Validation Contract for Open Document Spec (ODS): lint rules, rule severities, unknown-content behavior, diagnostic message format, and implementer checklists.
At a glance
- What this chapter defines: Binary compliance, the lint rule matrix, unknown-key behavior, and the implementer checklist.
- Why it exists: Conformance is what
ods lintcan prove, not what an author intended. - When you need it: You are wiring CI, reading an error ID, or implementing a linter.
- When you can skip it: You are still writing your first documents — common mistakes is enough.
- Learn this first: Run the workspace · Common mistakes
- Prerequisite chapters: core.md, keys.md
1. Conformance Language
The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, NOT RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted as described in BCP 14 (RFC 2119, RFC 8174) when, and only when, they appear in all capitals.
2. Binary Compliance Contract
Conformance for ODS metadata is defined by validation, not intention.
- An ODS workspace is evaluated as Compliant or Non-Compliant.
- When
ods lintis executed:- If zero errors are reported: the tool MUST exit with status code
0(Compliant). - If one or more errors are reported: the tool MUST exit with status code
1(Non-Compliant).
- If zero errors are reported: the tool MUST exit with status code
- Warnings (such as missing optional profile sections) SHOULD be reported to authors but MUST NOT cause a non-zero exit code. Unrecognized profile names are
PROF-001errors.
# CI Conformance Check
$ ods lint .
✓ Checked 48 documents across workspace.
✓ 0 errors, 2 warnings. Workspace is COMPLIANT.
$ echo $?
0
3. The Two Lifecycle Phases
ODS enforces clear separation between verification in CI and context resolution for AI agents:
| Phase | Command | What is Checked / Executed | Primary Purpose |
|---|---|---|---|
| Phase 1: Authoring & Verification | ods lint |
• YAML syntax • 3-tier key placement • DAG acyclicity (no cycles in depends)• File existence on disk for resources, code, and load• Absence of line numbers in code paths |
Enforces repository health, consistency, and zero dead links in CI. |
| Phase 2: AI Context Resolution | ods context <id> |
• Traverses depends up to max-depth (default: 2)• Ingests context.load text files• Prunes context.ignore and share: private• Emits unified bounded prompt payload |
Assembles deterministic prompt context within token budget. |
4. Normative Lint Rules Matrix
All conformant ODS linters MUST enforce the following validation rules:
| Category | Rule Identifier | Rule Condition | Severity | Remediation Action |
|---|---|---|---|---|
| Syntax | SYNTAX-001 |
Frontmatter MUST parse as valid YAML delimited by ---. |
Error | Fix YAML syntax error. |
SYNTAX-002 |
Frontmatter MUST NOT contain a title: key. |
Error | Remove title: from frontmatter; declare title in first # H1 body heading. |
|
| Placement | PLACE-001 |
tags MUST appear at the top level; MUST NOT be nested under ods:. |
Warning | Hoist tags to top-level frontmatter. |
PLACE-002 |
Engine keys (profile, status, depends, etc.) MUST be nested under ods:. |
Error | Nest engine keys under ods: mapping. |
|
PLACE-003 |
Document frontmatter MUST NOT contain workspace policy keys (spec, ignore, packs, specs, custom_profiles / custom-profiles). Those keys belong in root ods.toml. |
Error | Move the keys into ods.toml; do not keep a dual marker in index.md. |
|
| Workspace | WS-001 |
An ODS workspace MUST have root ods.toml with a non-empty spec. Root index.md / scalar ods: 0.1 is not a workspace marker. |
Error | Run ods init (writes ods.toml) then retry. |
| Enums | ENUM-001 |
ods.status MUST be one of draft, stable, deprecated, archived. |
Error | Change status to a recognized lifecycle state. |
ENUM-002 |
ods.share (when present) MUST be one of public, org, private. |
Error | Set share to public, org, or private. |
|
ENUM-003 |
ods.code[].role MUST be one of the 8 standard roles. |
Error | Change role to a valid standard role (e.g. entrypoint, implementation). |
|
| Graph | GRAPH-001 |
Document IDs MUST be unique across the workspace. | Error | Rename duplicate file or override via ods.id. |
GRAPH-002 |
ods.depends targets MUST resolve to existing documents. |
Error | Fix or remove dangling dependency path. | |
GRAPH-003 |
ods.related targets MUST resolve to existing documents. |
Error | Fix or remove dangling related path. | |
GRAPH-004 |
ods.depends graph MUST NOT contain cyclic dependency loops. |
Error | Break circular dependency loop using ods.related. |
|
| Assets | ASSET-001 |
ods.resources[].path MUST resolve to an existing file. |
Error | Fix path or verify file existence on disk. |
ASSET-002 |
ods.code[].path MUST resolve to an existing file. |
Error | Fix path or verify source code file on disk. | |
ASSET-003 |
ods.code[].path MUST NOT contain line number suffixes (e.g. :L45). |
Error | Remove :L45; use symbol field instead. |
|
ASSET-004 |
ods.context.load paths MUST resolve to existing files. |
Error | Fix or remove dangling context load path. | |
| Profiles | PROF-001 |
ods.profile MUST resolve to a known standard or registered custom profile. |
Error | Fix the profile name or define and register the profile at the path declared in ods.toml. |
PROF-002 |
Document SHOULD contain expected H2 or H3 sections (## or ###) for its declared profile. |
Warning | Add missing canonical section heading. | |
PROF-003 |
A document SHOULD contain each non-null top-level key listed by its selected custom profile’s required_keys. |
Warning | Add the missing key to top-level frontmatter; do not nest it under ods:. |
|
PROF-004 |
A document SHOULD NOT contain a top-level key listed by its selected custom profile’s forbidden_keys. |
Warning | Remove the forbidden key or choose a profile that permits it. | |
PROF-005 |
Every custom_profiles path in ods.toml MUST resolve to an existing Markdown file or profile directory. |
Error | Create the profile definition at the exact configured path or update the custom_profiles entry. |
|
PROF-006 |
ods.custom_profile MUST appear only in a profile-definition file selected by custom_profiles (or a registered pack). |
Error | Move the definition to its registered path and use ods.profile in ordinary documents. |
5. Commented Rule Violation Examples
5.1 Placement & Title Errors (SYNTAX-002, PLACE-002)
# ERRONEOUS CODE:
---
title: "Checkout Guide" # ERROR [SYNTAX-002]: title in frontmatter
profile: guide # ERROR [PLACE-002]: engine key at top level
ods:
tags: [billing] # WARNING [PLACE-001]: tags under ods:
---
# CORRECTED CODE:
---
tags:
- billing # CORRECT: tags at top level
ods:
profile: guide # CORRECT: engine key nested under ods:
status: stable
---
# Checkout Guide # CORRECT: Title declared as first H1 in body
5.2 Workspace Policy Keys in Frontmatter (PLACE-003, WS-001)
# ERRONEOUS CODE (root index.md is not a workspace):
---
ods: 0.1
packs:
- vendor/engineering-pack # ERROR [PLACE-003]: policy key in frontmatter
---
# CORRECTED CODE (root ods.toml):
spec = "0.1" # CORRECT [WS-001]: workspace marker
packs = ["vendor/engineering-pack"] # CORRECT: packs in ods.toml
5.3 Line Numbers in Code Bindings (ASSET-003)
# ERRONEOUS CODE:
ods:
code:
- path: src/checkout.ts:L45-L60 # ERROR [ASSET-003]: line numbers prohibited
role: implementation
# CORRECTED CODE:
ods:
code:
- path: src/checkout.ts # CORRECT: clean relative file path
role: implementation
symbol: processCheckout # CORRECT: refactor-resilient symbol reference
5.4 Cyclic Dependency Loops (GRAPH-004)
# ERRONEOUS CODE (Doc A depends on Doc B, Doc B depends on Doc A):
# In auth.md:
ods:
depends: [session.md]
# In session.md:
ods:
depends: [auth.md] # ERROR [GRAPH-004]: Cyclic dependency detected
# CORRECTED CODE:
# In auth.md:
ods:
depends: [session.md] # Hard prerequisite
# In session.md:
ods:
related: [auth.md] # CORRECT: Changed to soft related link (cycles permitted)
6. Unknown-Content Behavior (Normative)
| Encountered Content | Tooling Behavior |
|---|---|
Unknown Top-Level Frontmatter Key (e.g. layout, hero_image) |
Preserve and Ignore: Re-emit untouched during formatting and migrations. |
Top-Level Key Listed by required_keys |
Profile-Scoped Requirement: Validate presence for documents using the declaring custom profile; preserve the key and its value. |
Unknown Nested Key under ods: |
Report Warning: Warn author of unknown engine key; preserve during formatting. |
Unrecognized ods.profile |
Fatal Profile Error: Report PROF-001; do not fall back to note or another profile. |
Unknown code role |
Fatal Error: Reject immediately; projects MUST NOT invent custom code roles. |
Invalid ods.share value |
Fatal Error: Reject immediately to prevent unintended privacy leaks. |
Legacy Flat Engine Keys (without nested ods:) |
Migration Mode: Accept during read; format tooling (ods fmt --migrate) MUST nest under ods:. |
Workspace Policy Keys in Document Frontmatter (spec, ignore, packs, specs, custom_profiles) |
Fatal Error (PLACE-003): Move into root ods.toml. A missing ods.toml is WS-001, not a root index.md. |
7. Diagnostic Message Presentation
Conformant ODS tools SHOULD present diagnostic output in a short, directive format featuring:
- File location (
path:line:col) - Clear error description with Rule Identifier
- Actionable remediation (
Next: ...)
error[ASSET-003]: line numbers are prohibited in code paths
--> docs/guides/checkout.md:14:11
|
14 | - path: src/checkout.ts:L45-L60
| ^^^^^^^^^^^^^^^^^^^^^^^
= help: line numbers drift across commits. Use 'symbol: processCheckout' instead.
= next: remove ':L45-L60' from the path and add 'symbol: <name>'
8. Implementer Conformance Checklist
This checklist provides an actionable summary for developers building ODS parsers, linters, and runtime engines.
Frontmatter & Parser
- Parse frontmatter delimited by
---as YAML. - Preserve all unknown top-level frontmatter keys during read/write cycles.
- Enforce prohibition of
title:in frontmatter. - Enforce top-level placement for
description,tags,owner,created,updated. - Enforce nested
ods:placement for all engine keys.
Graph & DAG Engine
- Derive document ID from workspace-relative path without
.md. - Enforce unique document IDs across workspace.
- Validate that all
ods.dependsandods.relatedpaths resolve to real.mdfiles. - Perform cycle detection on
ods.dependsedges (reject cyclic graphs). - Compute backlinks dynamically on demand (never hand-written).
Assets & Code Engine
- Validate that all
ods.resourcespaths resolve on disk. - Validate that all
ods.codepaths resolve on disk. - Reject any
ods.code[].pathcontaining a line number suffix (:L...). - Validate that
ods.code[].rolebelongs to the 8 standard roles.
Profile & Discovery Engine
- Validate expected H2 or H3 headings (
##or###) for standard profiles by exact canonical section title; do not count H1 or H4+ headings. - Parse
ods.custom_profile.name,required_keys,optional_keys, andforbidden_keysfrom registered custom profile definitions. - Fail when any
custom_profilespath inods.tomlis missing, not a Markdown file, or otherwise cannot be loaded. - Fail when
ods.custom_profileappears outside a file selected bycustom_profilesor a registered pack. - Fail when
ods.profiledoes not resolve to a standard profile or a loaded custom profile; include the configured profile paths in the diagnostic. - Validate each selected custom profile’s
required_keysagainst top-level document frontmatter and emitPROF-003warnings for missing keys. - Emit
PROF-004warnings when selected profileforbidden_keysare present. - Resolve custom profiles registered in
ods.toml. - Support progressive CLI discovery without generating committed folder indexes.
- Treat root
ods.tomlwithspecas the only workspace marker (WS-001); reject a tree that has only rootindex.mdwithods: 0.1. - Error when document frontmatter contains
spec,ignore,packs,specs, orcustom_profiles(PLACE-003). - Record packs and custom profiles in
ods.toml, not in root index frontmatter.
Navigation & Reading Order
| ← Previous Chapter | 📑 Specification Index | Next Chapter → |
|---|---|---|
| 08. Workspace Config & Progressive Discovery | Open Document Spec (ODS) | 10. Scope & Architectural Non-Goals |