xdrs-core 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -25,8 +25,15 @@ Provides clear ownership by scope, predictable navigation, and reusable decision
25
25
  - XDRs are the central artifact of the framework and the authoritative policy for their scope, type, and subject. Supporting artifacts may explain, justify, or operationalize the decision, but they do not replace it.
26
26
  - XDRs MAY include a `## Metadata` section, but only when at least one supported metadata field is present. When used, `## Metadata` MUST appear immediately before `## Context and Problem Statement`.
27
27
  - Supported XDR metadata fields are:
28
+ - `Status:` Optional. Defines the lifecycle state of the decision. Allowed values are `Draft`, `Active`, and `Deprecated`. If omitted, the decision is treated as `Active`. Only `Active` decisions may be treated as current policy.
29
+ - `Valid:` Optional. Defines the time window in which an active decision may be treated as current. Use ISO dates only: `from YYYY-MM-DD`, `until YYYY-MM-DD`, or `from YYYY-MM-DD until YYYY-MM-DD`. If `from` is omitted, the decision takes effect immediately. If `until` is omitted, the decision remains valid indefinitely.
28
30
  - `Applied to:` Optional. A short description of the contexts in which the decision is applicable. Keep it under 40 words. If omitted, the decision should be interpreted as applying to all logically applicable elements according to the decision text itself. Examples: `Only frontend code`, `JavaScript projects`, `Performance-sensitive codebases`
29
- - `Validity:` Optional. Defines when the decision is active. Use ISO dates only: `from YYYY-MM-DD`, `until YYYY-MM-DD`, or `from YYYY-MM-DD until YYYY-MM-DD`. If `from` is omitted, the decision takes effect immediately. If `until` is omitted, the decision remains valid indefinitely. `Draft` or `Retired` mean the XDR should be ignored as an active rule or policy.
31
+ - Before using, enforcing, or citing an XDR as a current rule, humans and AI agents MUST decide whether the decision is in force for the current case.
32
+ - Check `Status:` first to determine whether the XDR is eligible to be used now. If `Status:` is omitted, treat it as `Active`. `Draft` and `Deprecated` decisions are background or history, not current policy.
33
+ - Check `Valid:` next to determine whether the current moment falls inside the decision's active date window. Not-yet-active and expired windows are not current policy.
34
+ - Check `Applied to:` next to determine whether the active, currently valid decision fits the current codebase, system, workflow, or audience.
35
+ - Check the decision context and implementation details last to determine any additional boundaries, exceptions, or qualifiers that metadata alone cannot express.
36
+ - If any check fails, the XDR MAY still be read as background, history, or context, but it MUST NOT be treated as a current requirement for that case.
30
37
  - Research documents MAY be added under the same subject to capture the exploration, findings, and proposals that backed a decision. Research is useful during elaboration, discussion, approval, retirement, and updates, but the XDR remains the source of truth.
31
38
  - Make it clear if an instruction is mandatory or advisory
32
39
  - Mandatory language: "must", "always", "never", "required", "mandatory"
@@ -56,7 +63,7 @@ Provides clear ownership by scope, predictable navigation, and reusable decision
56
63
  - Types in IDs: `adr`, `bdr`, `edr`
57
64
  - Define the next number of an XDR by checking what is the highest number present in the type+scope. Don't fill numbering gaps, as they might be old deleted XDRs and we should never reuse numbers of different documents/decisions. Numbering gaps are expected.
58
65
  - Decisions MUST be concise and reference other XDRs to avoid duplication
59
- - The `### Implementation Details` section SHOULD state relevant boundaries or exceptions and what a reader should do or avoid in common cases. Use `## Metadata` for short applicability or lifecycle markers and keep nuanced boundaries in the decision text.
66
+ - The `### Implementation Details` section SHOULD state relevant boundaries or exceptions and what a reader should do or avoid in common cases. Use `## Metadata` as the first-pass filter for whether the decision should be used at all, then keep nuanced boundaries in the decision text.
60
67
  - Use concise rules, examples, or `Do` / `Don't` lists only when they help a reader apply the decision correctly. Keep them short and decision-specific.
61
68
  - When research exists for a decision, the XDR SHOULD mention the related research documents after the `## Considered Options` list.
62
69
  - Never use emojis in contents
@@ -85,9 +92,10 @@ All XDRs MUST follow this template
85
92
 
86
93
  ## Metadata
87
94
 
88
- [Optional section. Omit the entire section when neither `Applied to:` nor `Validity:` is defined.]
95
+ [Optional section. Omit the entire section when none of `Status:`, `Valid:`, or `Applied to:` is defined. Readers decide whether to use the XDR by checking `Status:` first, treating omission as `Active`, then `Valid:`, then `Applied to:`, and finally the decision text itself.]
96
+ Status: [Optional. Use `Draft`, `Active`, or `Deprecated`. Defaults to `Active` when omitted]
97
+ Valid: [Optional. Use `from YYYY-MM-DD`, `until YYYY-MM-DD`, or `from YYYY-MM-DD until YYYY-MM-DD`]
89
98
  Applied to: [Optional short applicability scope, under 40 words]
90
- Validity: [Optional. Use `Draft`, `Retired`, `from YYYY-MM-DD`, `until YYYY-MM-DD`, or `from YYYY-MM-DD until YYYY-MM-DD`]
91
99
 
92
100
  ## Context and Problem Statement
93
101
 
@@ -141,9 +149,10 @@ Question: In the end, state explicitly the question that needs to be answered. E
141
149
  - `.xdrs/business-x/adrs/governance/010-security-and-secrets-management.md`
142
150
  - `.xdrs/_core/adrs/devops/001-multi-repo.md`
143
151
  - Metadata examples:
152
+ - `Status: Draft`
153
+ - `Status: Active`
154
+ - `Valid: from 2026-03-01 until 2026-12-31`
144
155
  - `Applied to: JavaScript projects`
145
- - `Validity: Draft`
146
- - `Validity: from 2026-03-01 until 2026-12-31`
147
156
 
148
157
  ```text
149
158
  subject/
@@ -31,6 +31,7 @@ Skills are procedures, XDRs are guardrails and decisions, Research documents cap
31
31
  Always create links back and forth between skills <-> XDRs when the relationship is direct, and link to related Research or Articles when they provide important context.
32
32
  - Skills are task-based artifacts. They should have a clear starting trigger, an expected end result, and enough detail for a human or agent to verify that the task finished correctly.
33
33
  - A skill is not policy by itself. If following a skill is mandatory, that obligation must come from an XDR or another explicit policy that references the skill.
34
+ - When a skill reads, operationalizes, or enforces XDRs, it MUST evaluate the XDR metadata first. `Status:` determines whether the decision is eligible to be used, and an omitted `Status:` must be treated as `Active`. `Valid:` determines whether that active decision is currently in force by date, `Applied to:` determines whether it fits the current task context, and the decision text itself determines any remaining boundaries. Skills must not treat inactive, out-of-window, or out-of-scope XDRs as current requirements.
34
35
  - Skills and XDRs have a many-to-many relationship: one skill may operationalize multiple XDRs, and one XDR may be executed through multiple skills in different contexts.
35
36
 
36
37
  Place a skill under the XDR type that matches the nature of the activity the skill performs:
@@ -17,6 +17,7 @@ Articles are Markdown documents placed inside a subject folder alongside decisio
17
17
  - Articles are views, not decisions. They summarize and synthesize content from XDRs, Research, and Skills but are NOT the source of truth. When there is a conflict between an article and a Decision Record, the Decision Record takes precedence.
18
18
  - Articles must reference the XDRs, Research documents, and Skills they synthesize. Never duplicate decision content; link back to the authoritative sources.
19
19
  - Articles may serve as indexes, combining related artifacts on a specific topic into a single navigable document.
20
+ - When an article tells readers which decisions to follow, it SHOULD distinguish currently usable XDRs from background-only ones by checking `Status:` first, treating omission as `Active`, `Valid:` second, `Applied to:` third, and the decision text itself last. Articles must not present Draft, Deprecated, inactive-date, out-of-window, or out-of-scope XDRs as current rules for the discussed context.
20
21
  - Articles must remain consistent with the XDRs, Research documents, and Skills they reference. When a referenced artifact changes, the article must be reviewed and updated.
21
22
  - Place an article in the subject folder that best matches its topic. If an article spans more than one subject, place it in `principles`.
22
23
  - For simple structure, flow, layout, or relationship indications, articles SHOULD prefer plain Markdown, tables, or ASCII art instead of external assets.
@@ -47,6 +47,16 @@ The easiest way to distinguish the central elements is by asking what job each o
47
47
  This separation matters because mixing these jobs into one file makes the system harder to search,
48
48
  harder to update, and harder for agents to apply correctly.
49
49
 
50
+ ### How to decide whether an XDR should be used
51
+
52
+ Before treating an XDR as a rule for the current case, check its metadata first.
53
+
54
+ - **Status first**: only `Active` decisions can be current policy, and omitted `Status` should be treated as `Active`. `Draft` and `Deprecated` are background or historical context.
55
+ - **Valid second**: if present, the current moment must fall inside the decision's date window.
56
+ - **Applied to third**: if present, the current codebase, workflow, system, or audience must fit that scope.
57
+ - **Decision text last**: the XDR's own context and implementation details still determine the final boundaries and exceptions.
58
+ - **Then enforce**: only decisions that pass those checks should be used as active requirements. The rest may still be useful background or historical context.
59
+
50
60
  ### How they relate over time
51
61
 
52
62
  The framework is easiest to understand as a lifecycle rather than a static folder tree.
@@ -122,6 +132,7 @@ Follow [_core-adr-001](../001-xdr-standards.md) strictly. Key rules:
122
132
 
123
133
  - Use **mandatory language** (`must`, `never`, `required`) for non-negotiable rules and
124
134
  **advisory language** (`should`, `recommended`) for guidance.
135
+ - Before citing an XDR as a requirement, check `Status` first, treating omission as `Active`, then `Valid`, then `Applied to`, and finally the decision text to confirm the decision is active and in scope for the current case.
125
136
  - Keep XDRs under 100 lines. Move procedural detail to a co-located Skill.
126
137
  - Keep exploratory option analysis in a co-located Research document instead of bloating the XDR.
127
138
  - Always update the scope+type index and the root index after adding or changing an XDR.
@@ -24,12 +24,16 @@ Performs a structured review of code changes or files against the XDRs in the re
24
24
 
25
25
  1. Gather all Decision Records from `.xdrs/index.md` starting from the working directory.
26
26
  - XDR scopes are controlled by nested folders; some are broad, others domain-specific.
27
- - Extract metadata first (validity status and applicability) to filter relevant XDRs before deep analysis. Treat `Validity: Draft` and `Validity: Retired` as inactive policy.
27
+ - Extract metadata first to decide whether each XDR should be used for the current review context.
28
+ - Check `Status:` first. Treat an omitted `Status:` as `Active`, and treat `Draft` and `Deprecated` XDRs as background only, not active policy.
29
+ - Check `Valid:` second. Keep only `Active` XDRs whose date window covers the current review moment.
30
+ - Check `Applied to:` third. Keep only active, in-window XDRs whose stated scope fits the files, systems, or workflows under review.
31
+ - Check the decision text itself last for additional boundaries or exceptions that metadata does not encode.
28
32
  2. Filter relevance based on file types, domains, and architectural patterns in scope.
29
33
 
30
34
  ### Phase 3: XDR Review
31
35
 
32
- 1. Cross-reference each file in scope against applicable XDRs.
36
+ 1. Cross-reference each file in scope against active, applicable XDRs.
33
37
  - **Drop any finding that cannot be traced to a specific rule in an Accepted XDR.** General good-practice observations, personal opinions, or inferred issues without an explicit XDR backing must not be reported.
34
38
  - Classify as ERROR (mandatory) or WARNING (advisory).
35
39
  - Include: location, description, XDR reference (file + line), suggestion.
@@ -50,7 +54,7 @@ Performs a structured review of code changes or files against the XDRs in the re
50
54
  ### Phase 5: Reporting
51
55
 
52
56
  **Report template**
53
- --------
57
+ ```text
54
58
  ### Code Review Against XDRs
55
59
  Scope: [scope identifier]
56
60
 
@@ -68,7 +72,7 @@ Scope: [scope identifier]
68
72
  - Errors: [count]
69
73
  - Warnings: [count]
70
74
  - Outcome: [PASS|FAIL]
71
- --------
75
+ ```
72
76
 
73
77
  ### Constraints
74
78
  - MUST NOT include any text or explanations outside the required output format.
@@ -84,6 +88,6 @@ Scope: [scope identifier]
84
88
 
85
89
  ## References
86
90
 
87
- - [_core-adr-001 - XDR standards](../../../.xdrs/_core/adrs/principles/001-xdr-standards.md)
88
- - [_core-adr-003 - Skill standards](../../../.xdrs/_core/adrs/principles/003-skill-standards.md)
91
+ - [_core-adr-001 - XDR standards](../../001-xdr-standards.md)
92
+ - [_core-adr-003 - Skill standards](../../003-skill-standards.md)
89
93
 
@@ -10,7 +10,7 @@ metadata:
10
10
 
11
11
  ## Overview
12
12
 
13
- Guides the creation of a well-structured XDR by following the standards in `_core-adr-001`, researching existing records for conflicts, checking redundancy across related artifacts, and iterating until the document is concise and decision-focused.
13
+ Guides the creation of a well-structured XDR by following the standards in `_core-adr-001`, researching existing records for conflicts, checking redundancy across related artifacts, and iterating until the document is concise, decision-focused, and clear about when the decision should be used.
14
14
 
15
15
  ## Instructions
16
16
 
@@ -71,8 +71,9 @@ Use the mandatory template from `001-xdr-standards`:
71
71
 
72
72
  ## Metadata
73
73
  [Optional. Include only when at least one metadata field is present]
74
+ Status: [Optional. Use Draft, Active, or Deprecated. Defaults to Active when omitted]
75
+ Valid: [Optional. Use from YYYY-MM-DD, until YYYY-MM-DD, or from YYYY-MM-DD until YYYY-MM-DD]
74
76
  Applied to: [Optional short applicability scope, under 40 words]
75
- Validity: [Optional. Use Draft, Retired, from YYYY-MM-DD, until YYYY-MM-DD, or from YYYY-MM-DD until YYYY-MM-DD]
76
77
 
77
78
  ## Context and Problem Statement
78
79
  [4 lines max: background, who is impacted, and the explicit question being answered]
@@ -93,9 +94,10 @@ Validity: [Optional. Use Draft, Retired, from YYYY-MM-DD, until YYYY-MM-DD, or f
93
94
  ```
94
95
 
95
96
  Mandatory rules to apply while drafting:
96
- - Include `## Metadata` only when `Applied to:` and/or `Validity:` adds value; omit the whole section when neither field is defined.
97
+ - Include `## Metadata` only when `Status:`, `Valid:`, and/or `Applied to:` adds value; omit the whole section when none of those fields is defined.
97
98
  - When present, place `## Metadata` immediately before `## Context and Problem Statement`.
98
- - Keep `Applied to:` under 40 words and use `Validity:` only with ISO dates or the special values `Draft` / `Retired`.
99
+ - Keep `Applied to:` under 40 words, use `Status:` only with `Draft`, `Active`, or `Deprecated`, remember that omitted `Status:` means `Active`, and use `Valid:` only with ISO date ranges.
100
+ - When metadata is present, write it so a reader can decide whether the XDR should be used for the current case without guessing. `Status:` controls lifecycle state, omitted `Status:` means `Active`, `Valid:` controls the active time window, `Applied to:` narrows the contexts where that active decision applies, and the decision text defines any remaining boundaries.
99
101
  - Use mandatory language ("must", "always", "never") only for hard requirements; use advisory language ("should", "recommended") for guidance.
100
102
  - Do not duplicate content already in referenced XDRs — link instead.
101
103
  - Keep the decision itself authoritative in the XDR. Supporting artifacts may elaborate, but they should not restate the full decision when a short reference is enough.
@@ -111,7 +113,7 @@ Mandatory rules to apply while drafting:
111
113
  Check every item before finalizing:
112
114
 
113
115
  1. **Length**: Is it under 100 lines? Trim verbose explanations. Move detailed skills to a separate file and link.
114
- 2. **Metadata**: If metadata exists, is it directly before Context, limited to `Applied to:` / `Validity:`, and omitted entirely when both are absent?
116
+ 2. **Metadata**: If metadata exists, is it directly before Context, limited to `Status:` / `Valid:` / `Applied to:`, omitted entirely when all three are absent, and specific enough for a reader to decide whether the XDR is active, currently valid, and applicable?
115
117
  3. **Originality**: Does every sentence add value that cannot be found in a generic web search? Remove obvious advice. Keep only the project-specific decision.
116
118
  4. **Clarity**: Is the chosen option unambiguous? Is the "why" clear in one reading?
117
119
  5. **Redundancy**: Is the XDR the primary source for the decision itself, with related documents linked instead of duplicated wherever possible?
@@ -47,7 +47,8 @@ Quick test:
47
47
 
48
48
  1. List `.xdrs/[scope]/[type]/[subject]/skills/` for existing skills. If one already covers the goal, extend or reference it instead of creating a duplicate.
49
49
  2. Read all XDRs relevant to the skill's domain to collect rules and cross-references.
50
- 3. Decide whether the skill is merely guidance or is being referenced by an XDR as a mandatory procedure. Do not encode policy in the skill unless it comes from a referenced XDR.
50
+ 3. Evaluate XDR metadata before operationalizing those rules. `Status:` decides whether a decision is eligible to be used, and omitted `Status:` means `Active`; `Valid:` decides whether that active decision is in force at the current moment, `Applied to:` decides whether it fits the intended task context, and the decision text defines any remaining boundaries. Keep inactive, out-of-window, or out-of-scope XDRs as background only.
51
+ 4. Decide whether the skill is merely guidance or is being referenced by an XDR as a mandatory procedure. Do not encode policy in the skill unless it comes from a referenced XDR.
51
52
 
52
53
  ### Phase 4: Write the SKILL.md
53
54
 
@@ -92,6 +93,7 @@ Rules:
92
93
  - Mention tools or prerequisites when they are required to complete the task reliably.
93
94
  - Do not duplicate content from referenced XDRs — link instead.
94
95
  - Do not present the skill itself as policy; mandatory behavior must come from referenced XDRs or other policy artifacts.
96
+ - When the skill depends on XDRs, make the activation logic and instructions consistent with the XDR metadata so the skill does not operationalize inactive or out-of-scope decisions.
95
97
  - Prefer plain Markdown, tables, or ASCII art for simple structure, flow, layout, or relationship indications.
96
98
  - If `SKILL.md` genuinely needs local images or supporting files, store them in `.xdrs/[scope]/[type]/[subject]/skills/[number]-[skill-name]/assets/` and link with a relative path.
97
99
  - No emojis. Lowercase filenames. Target under 500 lines.
@@ -43,8 +43,9 @@ If the article spans more than one subject, place it in `principles`.
43
43
  ### Phase 4: Research XDRs and Skills to Synthesize
44
44
 
45
45
  1. Read all XDRs, Research documents, and Skills relevant to the article topic across all scopes listed in `.xdrs/index.md`.
46
- 2. Identify the key points a reader needs to understand the topic end-to-end.
47
- 3. Collect XDR IDs and file paths for cross-references. Never copy decision text verbatim; link to it.
46
+ 2. Evaluate XDR metadata before synthesizing guidance. Use `Status:` to determine whether a decision is eligible to be current guidance, treating omitted `Status:` as `Active`; use `Valid:` to determine whether that active decision is in force for the article's time horizon, `Applied to:` to determine whether it fits the audience or context being discussed, and the decision text itself for any remaining applicability boundaries.
47
+ 3. Identify the key points a reader needs to understand the topic end-to-end.
48
+ 4. Collect XDR IDs and file paths for cross-references. Never copy decision text verbatim; link to it.
48
49
 
49
50
  ### Phase 5: Write the Article
50
51
 
@@ -71,6 +72,7 @@ Rules to apply while drafting:
71
72
 
72
73
  - Write for the stated audience; avoid jargon unexplained elsewhere.
73
74
  - Every factual claim must link back to the authoritative XDR or Skill.
75
+ - If the article advises readers what to do, clearly separate active/applicable XDRs from background, historical, or out-of-scope ones.
74
76
  - Never reproduce decision text verbatim; summarize and link.
75
77
  - Prefer plain Markdown, tables, or ASCII art for simple structure, flow, layout, or relationship indications.
76
78
  - If the article genuinely needs local images or supporting files, store them in `.xdrs/[scope]/[type]/[subject]/articles/assets/` and link with a relative path.
@@ -111,6 +113,6 @@ Rules to apply while drafting:
111
113
 
112
114
  ## References
113
115
 
114
- - [_core-adr-004 - Article standards](../../004-article-standards.md)
115
- - [_core-adr-006 - Research standards](../../006-research-standards.md)
116
- - [_core-adr-001 - XDR standards](../../001-xdr-standards.md)
116
+ - [_core-adr-004 - Article standards](../../../.xdrs/_core/adrs/principles/004-article-standards.md)
117
+ - [_core-adr-006 - Research standards](../../../.xdrs/_core/adrs/principles/006-research-standards.md)
118
+ - [_core-adr-001 - XDR standards](../../../.xdrs/_core/adrs/principles/001-xdr-standards.md)
package/README.md CHANGED
@@ -14,7 +14,7 @@ This project defines a standard for organizing XDRs that satisfies the following
14
14
 
15
15
  Every XDR package contains four types of documents:
16
16
 
17
- - **Decision Records (XDRs)** — Architectural (ADR), Business (BDR), or Engineering (EDR) records that capture a single decision, its rationale, and the rules that follow from it. They are the source of truth. An XDR may optionally start with a `Metadata` section for short applicability and validity markers.
17
+ - **Decision Records (XDRs)** — Architectural (ADR), Business (BDR), or Engineering (EDR) records that capture a single decision, its rationale, and the rules that follow from it. They are the source of truth. An XDR may optionally start with a `Metadata` section for short status, validity-window, and applicability markers, and readers should use that metadata to decide whether the decision is currently in force for their case. If `Status:` is omitted, treat the decision as `Active` by default.
18
18
  - **Research** — Exploratory documents that capture the problem being investigated, constraints or requirements, findings, and option tradeoffs that back a decision during its lifecycle. One research document may inform multiple downstream decisions, but it is not a replacement for the Decision Record.
19
19
  - **Skills** — Step-by-step procedural guides that can be followed by humans, AI agents, or both. Skills are task-based artifacts with a concrete outcome and should include enough detail to verify the task was completed correctly. A skill may start as a fully manual procedure and evolve toward partial or full AI automation over time. Co-located with the XDRs they implement.
20
20
  - **Articles** — Synthetic explanatory texts that combine information from multiple XDRs, Research documents, and Skills around a specific topic or audience. They never replace XDRs as source of truth.
@@ -57,7 +57,7 @@ The `lint` command reads `./.xdrs/**` from the given workspace path and checks c
57
57
  - research numbering uniqueness per `scope/type/subject/researches`
58
58
  - canonical index presence and link consistency
59
59
  - root index coverage for all discovered canonical indexes
60
- - XDR metadata section placement and `Applied to` / `Validity` field format
60
+ - XDR metadata section placement and `Status` / `Valid` / `Applied to` field format
61
61
  - local image and `assets/` links resolving inside the sibling `assets/` folder for each document
62
62
 
63
63
  Examples:
@@ -93,6 +93,7 @@ The folder layout, file naming, and document format are designed so that AI agen
93
93
  - Each XDR is a small, focused Markdown file (target under 100 lines), covering one decision.
94
94
  - The canonical index per scope and type lists all XDRs with short descriptions, enabling agents to identify relevant records without reading every file.
95
95
  - The root index at `.xdrs/index.md` provides a single entry point for discovery.
96
+ - XDR metadata gives agents a first-pass filter: check `Status` first, treating an omitted `Status` as `Active`; then check `Valid`, then `Applied to`, and finally the decision text itself to confirm the decision should be used in the current context.
96
97
  - Decisions cross-reference each other by XDR ID rather than duplicating content, keeping individual files concise.
97
98
  - Subject folders reduce the search space when a query maps to a known domain.
98
99
 
package/lib/lint.js CHANGED
@@ -279,10 +279,11 @@ function lintXdrMetadata(content, filePath, errors) {
279
279
  start: metadataLine + 1,
280
280
  end: (headingLines.find((lineIndex) => lineIndex > metadataLine) ?? lines.length) - 1
281
281
  };
282
+ const statusLineNumbers = findFieldLines(lines, ignoredLines, 'Status:');
282
283
  const appliedLineNumbers = findFieldLines(lines, ignoredLines, 'Applied to:');
283
- const validityLineNumbers = findFieldLines(lines, ignoredLines, 'Validity:');
284
+ const validLineNumbers = findFieldLines(lines, ignoredLines, 'Valid:');
284
285
 
285
- if (!metadataRange && (appliedLineNumbers.length > 0 || validityLineNumbers.length > 0)) {
286
+ if (!metadataRange && (statusLineNumbers.length > 0 || appliedLineNumbers.length > 0 || validLineNumbers.length > 0)) {
286
287
  errors.push(`XDR metadata fields require a ## Metadata section immediately before Context and Problem Statement: ${toDisplayPath(filePath)}`);
287
288
  return;
288
289
  }
@@ -291,28 +292,34 @@ function lintXdrMetadata(content, filePath, errors) {
291
292
  return;
292
293
  }
293
294
 
295
+ const metadataStatus = statusLineNumbers.filter((lineIndex) => isLineInsideRange(lineIndex, metadataRange));
294
296
  const metadataApplied = appliedLineNumbers.filter((lineIndex) => isLineInsideRange(lineIndex, metadataRange));
295
- const metadataValidity = validityLineNumbers.filter((lineIndex) => isLineInsideRange(lineIndex, metadataRange));
297
+ const metadataValid = validLineNumbers.filter((lineIndex) => isLineInsideRange(lineIndex, metadataRange));
296
298
 
297
- if (metadataApplied.length === 0 && metadataValidity.length === 0) {
299
+ if (metadataStatus.length === 0 && metadataApplied.length === 0 && metadataValid.length === 0) {
298
300
  errors.push(`XDR metadata section must be omitted when no metadata fields are defined: ${toDisplayPath(filePath)}`);
299
301
  }
300
302
 
303
+ if (metadataStatus.length > 1) {
304
+ errors.push(`XDR metadata must not repeat Status: ${toDisplayPath(filePath)}`);
305
+ }
306
+
301
307
  if (metadataApplied.length > 1) {
302
308
  errors.push(`XDR metadata must not repeat Applied to: ${toDisplayPath(filePath)}`);
303
309
  }
304
310
 
305
- if (metadataValidity.length > 1) {
306
- errors.push(`XDR metadata must not repeat Validity: ${toDisplayPath(filePath)}`);
311
+ if (metadataValid.length > 1) {
312
+ errors.push(`XDR metadata must not repeat Valid: ${toDisplayPath(filePath)}`);
307
313
  }
308
314
 
309
- for (const lineIndex of [...appliedLineNumbers, ...validityLineNumbers]) {
315
+ for (const lineIndex of [...statusLineNumbers, ...appliedLineNumbers, ...validLineNumbers]) {
310
316
  if (!isLineInsideRange(lineIndex, metadataRange)) {
311
317
  errors.push(`XDR metadata fields must be declared inside ## Metadata: ${toDisplayPath(filePath)}`);
312
318
  break;
313
319
  }
314
320
  }
315
321
 
322
+ let previousFieldOrder = -1;
316
323
  for (let lineIndex = metadataRange.start; lineIndex <= metadataRange.end; lineIndex += 1) {
317
324
  if (ignoredLines[lineIndex]) {
318
325
  continue;
@@ -321,10 +328,26 @@ function lintXdrMetadata(content, filePath, errors) {
321
328
  if (trimmed === '') {
322
329
  continue;
323
330
  }
324
- if (!trimmed.startsWith('Applied to:') && !trimmed.startsWith('Validity:')) {
325
- errors.push(`XDR metadata section only supports Applied to: and Validity: fields: ${toDisplayPath(filePath)}`);
331
+ const currentFieldOrder = trimmed.startsWith('Status:')
332
+ ? 0
333
+ : trimmed.startsWith('Valid:')
334
+ ? 1
335
+ : trimmed.startsWith('Applied to:')
336
+ ? 2
337
+ : -1;
338
+ if (currentFieldOrder === -1) {
339
+ errors.push(`XDR metadata section only supports Status:, Valid:, and Applied to: fields: ${toDisplayPath(filePath)}`);
326
340
  break;
327
341
  }
342
+ if (currentFieldOrder < previousFieldOrder) {
343
+ errors.push(`XDR metadata fields must be ordered as Status:, Valid:, Applied to: ${toDisplayPath(filePath)}`);
344
+ break;
345
+ }
346
+ previousFieldOrder = currentFieldOrder;
347
+ }
348
+
349
+ if (metadataStatus.length === 1) {
350
+ lintStatusField(lines[metadataStatus[0]], filePath, errors);
328
351
  }
329
352
 
330
353
  if (metadataApplied.length === 1) {
@@ -336,33 +359,37 @@ function lintXdrMetadata(content, filePath, errors) {
336
359
  }
337
360
  }
338
361
 
339
- if (metadataValidity.length === 1) {
340
- lintValidityField(lines[metadataValidity[0]], filePath, errors);
362
+ if (metadataValid.length === 1) {
363
+ lintValidField(lines[metadataValid[0]], filePath, errors);
341
364
  }
342
365
  }
343
366
 
344
- function lintValidityField(line, filePath, errors) {
345
- const value = line.slice('Validity:'.length).trim().replace(/\.$/, '');
367
+ function lintStatusField(line, filePath, errors) {
368
+ const value = line.slice('Status:'.length).trim().replace(/\.$/, '');
346
369
 
347
- if (value === 'Draft' || value === 'Retired') {
348
- return;
370
+ if (value !== 'Draft' && value !== 'Active' && value !== 'Deprecated') {
371
+ errors.push(`XDR Status: must be Draft, Active, or Deprecated: ${toDisplayPath(filePath)}`);
349
372
  }
373
+ }
374
+
375
+ function lintValidField(line, filePath, errors) {
376
+ const value = line.slice('Valid:'.length).trim().replace(/\.$/, '');
350
377
 
351
- const validityMatch = value.match(/^(?:from\s+(\d{4}-\d{2}-\d{2}))?(?:\s+until\s+(\d{4}-\d{2}-\d{2}))?$/);
352
- if (!validityMatch || (!validityMatch[1] && !validityMatch[2])) {
353
- errors.push(`XDR Validity: must be Draft, Retired, from YYYY-MM-DD, until YYYY-MM-DD, or from YYYY-MM-DD until YYYY-MM-DD: ${toDisplayPath(filePath)}`);
378
+ const validMatch = value.match(/^(?:from\s+(\d{4}-\d{2}-\d{2})(?:\s+until\s+(\d{4}-\d{2}-\d{2}))?|until\s+(\d{4}-\d{2}-\d{2}))$/);
379
+ if (!validMatch) {
380
+ errors.push(`XDR Valid: must be from YYYY-MM-DD, until YYYY-MM-DD, or from YYYY-MM-DD until YYYY-MM-DD: ${toDisplayPath(filePath)}`);
354
381
  return;
355
382
  }
356
383
 
357
- const fromDate = validityMatch[1];
358
- const untilDate = validityMatch[2];
384
+ const fromDate = validMatch[1];
385
+ const untilDate = validMatch[2] ?? validMatch[3];
359
386
  if ((fromDate && !isIsoDate(fromDate)) || (untilDate && !isIsoDate(untilDate))) {
360
- errors.push(`XDR Validity: must use ISO dates in YYYY-MM-DD format: ${toDisplayPath(filePath)}`);
387
+ errors.push(`XDR Valid: must use ISO dates in YYYY-MM-DD format: ${toDisplayPath(filePath)}`);
361
388
  return;
362
389
  }
363
390
 
364
391
  if (fromDate && untilDate && fromDate > untilDate) {
365
- errors.push(`XDR Validity: from date must be on or before until date: ${toDisplayPath(filePath)}`);
392
+ errors.push(`XDR Valid: from date must be on or before until date: ${toDisplayPath(filePath)}`);
366
393
  }
367
394
  }
368
395
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xdrs-core",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "A standard way to organize Decision Records (XDRs) across scopes, subjects, and teams so that AI agents can reliably query and follow them.",
5
5
  "repository": {
6
6
  "type": "git",