xdrs-core 0.38.1 → 0.38.4
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.
- package/.xdrs/_core/adrs/index.md +1 -1
- package/.xdrs/_core/adrs/principles/001-xdrs-core.md +2 -2
- package/.xdrs/_core/adrs/principles/002-policy-standards.md +6 -3
- package/.xdrs/_core/adrs/principles/008-policy-structured-standards.md +74 -0
- package/.xdrs/_core/adrs/principles/012-reference-scope-type.md +1 -1
- package/.xdrs/_core/adrs/principles/skills/002-write-policy/SKILL.md +2 -2
- package/.xdrs/_core/index.md +1 -1
- package/lib/lint.js +13 -2
- package/lib/lint.test.js +111 -1
- package/package.json +1 -1
- package/.xdrs/_core/adrs/principles/008-xdr-standards-structured.md +0 -83
|
@@ -13,7 +13,7 @@ Foundational standards, principles, and guidelines.
|
|
|
13
13
|
- [_core-adr-policy-005](principles/005-semantic-versioning-for-xdrs-packages.md) - **Semantic versioning for XDRS packages** — How to version XDRS packages to communicate upgrade impact
|
|
14
14
|
- [_core-adr-policy-006](principles/006-research-standards.md) - **Research standards** — How to structure research documents backing Policy decisions
|
|
15
15
|
- [_core-adr-policy-007](principles/007-plan-standards.md) - **Plan standards** — How to structure ephemeral execution plans that implement decisions
|
|
16
|
-
- [_core-adr-policy-008](principles/008-
|
|
16
|
+
- [_core-adr-policy-008](principles/008-policy-structured-standards.md) - **Policy structured standards** — How to expose individually referenceable numbered rules inside a Policy when external citation by identifier is required
|
|
17
17
|
- [_core-adr-policy-009](principles/009-presentation-standards.md) - **Presentation standards** — How to structure Marp slide presentations that support XDRS documents
|
|
18
18
|
- [_core-adr-policy-010](principles/010-scope-governance.md) - **Scope governance** — How to define custom scope types, scope-local standards, and how all governance mechanisms apply with their precedence chain
|
|
19
19
|
- [_core-adr-policy-011](principles/011-core-scope-type.md) - **core scope type** — Defines the `core` scope type: meta-governance scopes that hold writing standards, templates, and process guidance for a domain
|
|
@@ -144,8 +144,8 @@ Policies can be of different kinds, depending on the nature of the decision:
|
|
|
144
144
|
- Canonical index requirements:
|
|
145
145
|
- Organize XDRS documents by subject for easier navigation
|
|
146
146
|
- Add a short description of what this scope is about (responsibilities, general worries, teams involved, link to discussion process, etc)
|
|
147
|
-
- Add
|
|
148
|
-
- Each XDRS element entry
|
|
147
|
+
- Add links to related scope indexes that this scope might override or be overridden by (scopes listed last override earlier ones on the same topic).
|
|
148
|
+
- Each XDRS element entry MUST include a short description. SHOULD use an imperative statement or the question it answers (<15 words). Example: "Use this while planning a new feature", "What communication tone we use with our customers?"
|
|
149
149
|
- Outside the scopes, keep a root index in `[xdrs-root]/index.md` that links to each scope index (`[xdrs-root]/[scope]/index.md`). Add the text "XDRS scopes listed last override the ones listed first". The root index MUST NOT link directly to type indexes; readers navigate from the scope index to the type indexes. Use the link text pattern `View scope [scope_name]` for each scope link (e.g. `[View scope myteam] linking to (myteam/index.md)`).
|
|
150
150
|
- MUST verify if indexes are up to date after making changes
|
|
151
151
|
- **Scope index**
|
|
@@ -28,7 +28,7 @@ Policy documents are the authoritative source of truth for their scope, type, an
|
|
|
28
28
|
| `name` | Yes | 1-64 characters. Lowercase letters, numbers, hyphens, and leading underscores only. MUST NOT end with a hyphen. MUST NOT contain consecutive hyphens. MUST match the document identifier from the heading: `[scope]-[type]-policy-[number]-[short-title]`. |
|
|
29
29
|
| `description` | Yes | 1-1024 characters. Describes what this decision is about and when to use it. SHOULD include keywords that help agents identify when to apply it. |
|
|
30
30
|
| `apply-to` | Yes | Short description of contexts this decision is applicable to. Keep it under 40 words. Use `All scopes` when the decision applies broadly. Examples: `Only frontend code`, `JavaScript projects`, `All scopes`. |
|
|
31
|
-
| `valid-from` | Yes | ISO date (`YYYY-MM-DD`) indicating from when this decision MUST be enforced. Before this date it SHOULD be used everywhere possible, but compliance is not enforced during reviews until after this date. Defaults to the date the Policy was created. When updating an existing Policy whose `valid-from` date has already passed, preserve the original date—
|
|
31
|
+
| `valid-from` | Yes | ISO date (`YYYY-MM-DD`) indicating from when this decision MUST be enforced. Before this date it SHOULD be used everywhere possible, but compliance is not enforced during reviews until after this date. Defaults to the date the Policy was created. When updating an existing Policy whose `valid-from` date has already passed, preserve the original date—it MUST NOT be updated to the current date. The historical date shows when the policy was originally enabled and is important for understanding policy evolution. |
|
|
32
32
|
| `license` | No | SPDX license expression (e.g. `MIT`, `Apache-2.0`, `CC-BY-4.0`). Indicates the license under which the document content is shared. If omitted, the license is governed by the repository or package defaults. |
|
|
33
33
|
| `metadata` | No | Arbitrary key-value map for additional properties not defined by this spec. |
|
|
34
34
|
|
|
@@ -62,6 +62,8 @@ Policy documents are the authoritative source of truth for their scope, type, an
|
|
|
62
62
|
- Types in IDs: `adr-policy`, `bdr-policy`, `edr-policy`
|
|
63
63
|
- Define the next number of a Policy by checking what is the highest number present in the type+scope. Don't fill numbering gaps, as they might be old deleted Policies and we MUST NOT reuse numbers of different documents/decisions. Numbering gaps are expected.
|
|
64
64
|
- Policies MUST be concise and reference other Policies to avoid duplication.
|
|
65
|
+
- Policies MUST NOT contain duplicated content: the same rule or information MUST NOT appear more than once in the document, whether stated identically or rephrased. Consolidate into a single authoritative statement and reference it where needed.
|
|
66
|
+
- Policies MUST NOT contain conflicting content: all rules and statements within the same document MUST be consistent with each other.
|
|
65
67
|
- The `### Details` section SHOULD state relevant boundaries or exceptions and what a reader SHOULD do or avoid in common cases. Use the frontmatter fields `apply-to` and `valid-from` as the first-pass filter for applicability, then keep nuanced boundaries in the decision text.
|
|
66
68
|
- Use concise rules, examples, `Allowed` / `Disallowed` lists or checklists with required items to help the reader apply the decision correctly. Keep them short and decision-specific.
|
|
67
69
|
- Policies MUST NOT include historical change notes or descriptions of what changed from a previous version. State only the current rule that MUST be followed. Historical context is available via git history or versioned packages.
|
|
@@ -69,7 +71,8 @@ Policy documents are the authoritative source of truth for their scope, type, an
|
|
|
69
71
|
- When a policy covers elements that could be confused with each other, include explicit disambiguation statements clarifying the distinction before stating the rules for each.
|
|
70
72
|
- A "why" explanation for a policy rule MAY only be included if it is brief, non-obvious, relevant to the reader, and not longer than the rule itself.
|
|
71
73
|
- Rules MUST focus on what is required or forbidden. Explanations of why a rule exists belong in a Research document, not in the Policy itself. Link to the relevant research when the rationale is important for adoption.
|
|
72
|
-
-
|
|
74
|
+
- Each policy rule and rule block MUST be unambiguous: it MUST be possible to clearly follow, check, and discuss it without requiring additional interpretation.
|
|
75
|
+
- When the decision defines strong policies or rules that SHOULD be stated explicitly as stable rule blocks, or when other documents, skills, or agents need to cite those rules individually by identifier, the Policy MUST follow the extension [_core-adr-policy-008 - Policy structured standards](008-policy-structured-standards.md) instead of using plain bullet lists for those rules.
|
|
73
76
|
- Conflict handling applies to Policy documents:
|
|
74
77
|
- For cross-scope overrides, document the decision conflict in the Policy `## Conflicts` section of the Policy that overrides another scope.
|
|
75
78
|
- **Within-scope conflicts:** Policies within the same type+scope MUST NOT conflict. If two Policies appear to conflict, one SHOULD be updated, removed, or the conflict resolved through a new Policy.
|
|
@@ -158,4 +161,4 @@ Question: In the end, state explicitly the question that needs to be answered. E
|
|
|
158
161
|
- [_core-adr-policy-003 - Skill standards](003-skill-standards.md)
|
|
159
162
|
- [_core-adr-policy-004 - Article standards](004-article-standards.md)
|
|
160
163
|
- [_core-adr-policy-006 - Research standards](006-research-standards.md)
|
|
161
|
-
- [_core-adr-policy-008 - Policy standards
|
|
164
|
+
- [_core-adr-policy-008 - Policy structured standards](008-policy-structured-standards.md) - Extension for Policies that expose individually referenceable rules
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: _core-adr-policy-008-policy-structured-standards
|
|
3
|
+
description: Extends policy-standards with a numbered rule format for Policy documents that define strong policies or rules, or need individually referenceable items. Use when a Policy must expose explicit rule blocks that other documents or skills may cite by identifier.
|
|
4
|
+
apply-to: Policy documents requiring structured rule blocks
|
|
5
|
+
valid-from: 2025-01-01
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# _core-adr-policy-008: Policy structured standards
|
|
9
|
+
|
|
10
|
+
## Context and Problem Statement
|
|
11
|
+
|
|
12
|
+
Some Policy documents define strong rules or constraints that must be individually referenceable by other documents, skills, or automated agents. The standard policy format from `_core-adr-policy-002` does not specify how such numbered rule blocks should be structured, titled, or cited. Without a consistent format, citations become ambiguous and tools cannot reliably locate referenced rules.
|
|
13
|
+
|
|
14
|
+
## Decision Outcome
|
|
15
|
+
|
|
16
|
+
**Numbered rule blocks with stable identifiers, normative language, and dot-notation citations**
|
|
17
|
+
|
|
18
|
+
Policies that define strong or frequently-cited rules MUST use a numbered rule block format. Each rule receives a stable two-digit identifier, a lowercase kebab-case title, and a body with at least one normative keyword. Citations MUST use dot-notation referencing the exact rule identifier.
|
|
19
|
+
|
|
20
|
+
### Details
|
|
21
|
+
|
|
22
|
+
#### 01-always-use-numbered-rules-for-strong-or-referenceable-policies
|
|
23
|
+
|
|
24
|
+
A Policy MUST use numbered rule blocks when it defines strong rules that must be stable and referenceable. Rules MUST NOT be added for cosmetic organization only. Policies without strong rule sets SHOULD follow `_core-adr-policy-002-policy-standards` instead.
|
|
25
|
+
|
|
26
|
+
#### 02-rule-numbering-must-be-stable
|
|
27
|
+
|
|
28
|
+
Rule numbers MUST NOT be reused within the same document. When a rule is removed, its number is permanently retired. Gaps MUST NOT be filled by renumbering remaining rules.
|
|
29
|
+
|
|
30
|
+
#### 03-rule-body-must-use-normative-language
|
|
31
|
+
|
|
32
|
+
Every rule body MUST contain at least one normative term (MUST, SHOULD, MAY, etc.) as defined in `_core-adr-policy-001`. Rule bodies without normative language MUST NOT be published.
|
|
33
|
+
|
|
34
|
+
#### 04-citations-must-use-exact-identifiers
|
|
35
|
+
|
|
36
|
+
Citations MUST use the exact dot-notation form: `policy-name.NN-short-rule-title-in-kebab-case`. Prose references such as "see rule 3" or "the third rule" MUST NOT be used.
|
|
37
|
+
|
|
38
|
+
#### 05-rule-title-must-be-all-lowercase
|
|
39
|
+
|
|
40
|
+
Rule titles MUST be all lowercase. Uppercase letters MUST NOT appear in rule titles, including normative keywords (e.g. `01-code-must-be-linted`, not `01-code-MUST-be-linted`).
|
|
41
|
+
|
|
42
|
+
#### 06-normative-keywords-must-not-use-emphasis-marks
|
|
43
|
+
|
|
44
|
+
Normative keywords in rule bodies MUST be written as plain text. Bold or italic markers around normative keywords MUST NOT be used.
|
|
45
|
+
|
|
46
|
+
#### 07-rule-title-should-include-normative-keyword-in-simple-cases
|
|
47
|
+
|
|
48
|
+
A rule title SHOULD include a normative keyword when the rule can be stated clearly in a short phrase. For complex rules, the title MAY omit normative language, provided the rule body contains it.
|
|
49
|
+
|
|
50
|
+
#### 08-rule-block-must-use-standard-syntax
|
|
51
|
+
|
|
52
|
+
Each rule MUST be written as a level-4 heading with a two-digit zero-padded sequence number followed by a kebab-case title, and a body paragraph:
|
|
53
|
+
|
|
54
|
+
```markdown
|
|
55
|
+
#### [NN]-[short-rule-title-in-kebab-case]
|
|
56
|
+
[Rule body using normative language per _core-adr-policy-001. Under 500 words.]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### 09-citations-must-use-dot-notation
|
|
60
|
+
|
|
61
|
+
Citations MUST use dot-notation where `policy-name` matches the `name` frontmatter field and the rule identifier after the dot matches the heading text exactly:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
policy-name.NN-short-rule-title-in-kebab-case
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Examples:
|
|
68
|
+
- `_core-adr-policy-008-policy-structured-standards.01-always-use-numbered-rules-for-strong-or-referenceable-policies`
|
|
69
|
+
- `_local-bdr-policy-003-data-retention-policy.02-purge-schedule-for-pii`
|
|
70
|
+
|
|
71
|
+
## References
|
|
72
|
+
|
|
73
|
+
- [_core-adr-policy-001 - XDRS core](001-xdrs-core.md)
|
|
74
|
+
- [_core-adr-policy-002 - Policy standards](002-policy-standards.md)
|
|
@@ -35,7 +35,7 @@ Use `scope-type: reference` when the scope contains:
|
|
|
35
35
|
- Business area procedure standards: how sales processes SHOULD be conducted, how customer data MUST be handled, how marketing communications MUST comply with applicable regulations.
|
|
36
36
|
- Operational compliance guidelines: finance controls, accounting procedures, public communication standards, customer data management rules.
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
`scope-type: reference` MUST NOT be used for scopes that represent a live service, an active team, or a production system. Use `scope-type: platform` for those.
|
|
39
39
|
|
|
40
40
|
#### 03-naming-convention
|
|
41
41
|
|
|
@@ -78,7 +78,7 @@ Choose a title that clearly states the question this Policy answers, not the ans
|
|
|
78
78
|
Use the mandatory template from `002-policy-standards`:
|
|
79
79
|
|
|
80
80
|
**Check if the decision requires a structured set of rules:**
|
|
81
|
-
If the decision defines strong rules or policies that must be stated explicitly, or if other documents, skills, or agents have a clear need to reference individual rules, you MUST apply the structured rule format from `_core-adr-policy-008-policy-standards
|
|
81
|
+
If the decision defines strong rules or policies that must be stated explicitly, or if other documents, skills, or agents have a clear need to reference individual rules, you MUST apply the structured rule format from `_core-adr-policy-008-policy-structured-standards`. This means:
|
|
82
82
|
- Place each rule as a numbered heading block inside `### Details`.
|
|
83
83
|
- Use the format:
|
|
84
84
|
#### [NN]-[short-descriptive-title-in-kebab-case]
|
|
@@ -101,7 +101,7 @@ Access logs must be retained for at least 90 days and reviewed monthly for suspi
|
|
|
101
101
|
All external integrations should be reviewed annually for compliance with current security standards.
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
Refer to `_core-adr-policy-008-policy-standards
|
|
104
|
+
Refer to `_core-adr-policy-008-policy-structured-standards` for full requirements and citation syntax.
|
|
105
105
|
|
|
106
106
|
```
|
|
107
107
|
---
|
package/.xdrs/_core/index.md
CHANGED
|
@@ -29,7 +29,7 @@ The core architectural decision [_core-adr-policy-001](adrs/principles/001-xdrs-
|
|
|
29
29
|
Each artifact type has its own writing standard:
|
|
30
30
|
|
|
31
31
|
- **Policy documents** follow [_core-adr-policy-002](adrs/principles/002-policy-standards.md), which defines the mandatory template, frontmatter metadata, applicability rules, conflict handling, and word limits that keep decisions concise and authoritative.
|
|
32
|
-
- **Structured Policies** with individually referenceable rules follow the extension [_core-adr-policy-008](adrs/principles/008-
|
|
32
|
+
- **Structured Policies** with individually referenceable rules follow the extension [_core-adr-policy-008](adrs/principles/008-policy-structured-standards.md), adding numbered rule blocks and a dot-notation citation syntax.
|
|
33
33
|
- **Skills** follow [_core-adr-policy-003](adrs/principles/003-skill-standards.md), using the agentskills format so they work for both humans and AI agents on an automation gradient from fully manual to fully automated.
|
|
34
34
|
- **Articles** follow [_core-adr-policy-004](adrs/principles/004-article-standards.md), providing synthetic views that combine and link multiple Policies, research, and skills without replacing them as the source of truth.
|
|
35
35
|
- **Research** follows [_core-adr-policy-006](adrs/principles/006-research-standards.md), using an IMRAD-based structure for studies that back decisions with reproducible evidence.
|
package/lib/lint.js
CHANGED
|
@@ -38,6 +38,7 @@ const RESEARCH_MAX_WORDS = 5000;
|
|
|
38
38
|
const SKILL_MAX_WORDS = 6500;
|
|
39
39
|
|
|
40
40
|
const NORMATIVE_KEYWORDS_RE = /\bMUST NOT\b|\bMUST\b|\bSHOULD NOT\b|\bSHOULD\b|\bMAY\b|\bREQUIRED\b|\bOPTIONAL\b/;
|
|
41
|
+
const NORMATIVE_EMPHASIS_RE = /(\*{1,2}|_{1,2})(MUST NOT|SHOULD NOT|MUST|SHOULD|MAY|REQUIRED|OPTIONAL|always|never|mandatory|recommended|advised|preferably|possibly|optionally)(\*{1,2}|_{1,2})/i;
|
|
41
42
|
|
|
42
43
|
const RESEARCH_SECTION_LIMITS = {
|
|
43
44
|
'## Abstract': 200,
|
|
@@ -1623,7 +1624,11 @@ function lintStructuredRuleBlocks(content, filePath, errors) {
|
|
|
1623
1624
|
}
|
|
1624
1625
|
|
|
1625
1626
|
if (title.length === 0 || !/^[a-z][a-z0-9-]*$/.test(title)) {
|
|
1626
|
-
|
|
1627
|
+
if (/[A-Z]/.test(title)) {
|
|
1628
|
+
errors.push(`Policy structured rule title must be all lowercase ("${title}"): ${toDisplayPath(filePath)} [_core-adr-policy-008.05-rule-title-must-be-all-lowercase]`);
|
|
1629
|
+
} else {
|
|
1630
|
+
errors.push(`Policy structured rule title must be in kebab-case ("${title}"): ${toDisplayPath(filePath)} [_core-adr-policy-008.01-always-use-numbered-rules-for-strong-or-referenceable-policies]`);
|
|
1631
|
+
}
|
|
1627
1632
|
}
|
|
1628
1633
|
|
|
1629
1634
|
const wordCount = title.split('-').filter(Boolean).length;
|
|
@@ -1646,10 +1651,16 @@ function lintStructuredRuleBlocks(content, filePath, errors) {
|
|
|
1646
1651
|
}
|
|
1647
1652
|
}
|
|
1648
1653
|
const ruleBodyText = lines.slice(bodyStart, bodyEnd).join('\n');
|
|
1654
|
+
const ruleBodyNonCodeLines = lines.slice(bodyStart, bodyEnd).filter((_, idx) => !ignoredLines[bodyStart + idx]);
|
|
1655
|
+
const ruleBodyTextForEmphasis = ruleBodyNonCodeLines.join('\n');
|
|
1649
1656
|
|
|
1650
|
-
if (!NORMATIVE_KEYWORDS_RE.test(
|
|
1657
|
+
if (!NORMATIVE_KEYWORDS_RE.test(ruleBodyTextForEmphasis)) {
|
|
1651
1658
|
errors.push(`Policy structured rule body must contain normative language (MUST/SHOULD/MAY) in "${number}-${title}": ${toDisplayPath(filePath)} [_core-adr-policy-008.03-rule-body-must-use-normative-language]`);
|
|
1652
1659
|
}
|
|
1660
|
+
|
|
1661
|
+
if (NORMATIVE_EMPHASIS_RE.test(ruleBodyTextForEmphasis)) {
|
|
1662
|
+
errors.push(`Policy structured rule body must not use bold or italic marks around normative keywords in "${number}-${title}": ${toDisplayPath(filePath)} [_core-adr-policy-008.06-normative-keywords-must-not-use-emphasis-marks]`);
|
|
1663
|
+
}
|
|
1653
1664
|
}
|
|
1654
1665
|
}
|
|
1655
1666
|
|
package/lib/lint.test.js
CHANGED
|
@@ -2651,7 +2651,7 @@ test('reports structured rule block with non-kebab-case title', () => {
|
|
|
2651
2651
|
'.xdrs/_local/adrs/principles/001-main.md': xdrDocument([
|
|
2652
2652
|
'### Details',
|
|
2653
2653
|
'',
|
|
2654
|
-
'#### 01-
|
|
2654
|
+
'#### 01-my rule title',
|
|
2655
2655
|
'',
|
|
2656
2656
|
'This rule MUST be followed.',
|
|
2657
2657
|
].join('\n')),
|
|
@@ -2709,6 +2709,33 @@ test('reports structured rule block body missing normative language', () => {
|
|
|
2709
2709
|
expect(result.errors.join('\n')).toContain('[_core-adr-policy-008.03-rule-body-must-use-normative-language]');
|
|
2710
2710
|
});
|
|
2711
2711
|
|
|
2712
|
+
test('reports structured rule block body with normative language only inside a code block', () => {
|
|
2713
|
+
const workspaceRoot = createWorkspace('structured-rule-normative-in-code-block', {
|
|
2714
|
+
'.xdrs/index.md': rootIndex(),
|
|
2715
|
+
'.xdrs/_local/adrs/index.md': localAdrIndex([
|
|
2716
|
+
'- [001-main](principles/001-main.md) - Main decision'
|
|
2717
|
+
]),
|
|
2718
|
+
'.xdrs/_local/adrs/principles/001-main.md': xdrDocument([
|
|
2719
|
+
'### Details',
|
|
2720
|
+
'',
|
|
2721
|
+
'#### 01-my-rule',
|
|
2722
|
+
'',
|
|
2723
|
+
'Here is an example:',
|
|
2724
|
+
'',
|
|
2725
|
+
'```',
|
|
2726
|
+
'You MUST do this.',
|
|
2727
|
+
'```',
|
|
2728
|
+
'',
|
|
2729
|
+
'No normative language in prose.',
|
|
2730
|
+
].join('\n')),
|
|
2731
|
+
});
|
|
2732
|
+
|
|
2733
|
+
const result = lintWorkspace(workspaceRoot);
|
|
2734
|
+
|
|
2735
|
+
expect(result.errors.join('\n')).toContain('structured rule body must contain normative language');
|
|
2736
|
+
expect(result.errors.join('\n')).toContain('[_core-adr-policy-008.03-rule-body-must-use-normative-language]');
|
|
2737
|
+
});
|
|
2738
|
+
|
|
2712
2739
|
test('accepts valid structured rule blocks', () => {
|
|
2713
2740
|
const workspaceRoot = createWorkspace('structured-rule-valid', {
|
|
2714
2741
|
'.xdrs/index.md': rootIndex(),
|
|
@@ -2733,6 +2760,89 @@ test('accepts valid structured rule blocks', () => {
|
|
|
2733
2760
|
expect(result.errors.join('\n')).not.toContain('structured rule');
|
|
2734
2761
|
});
|
|
2735
2762
|
|
|
2763
|
+
test('reports structured rule block title with uppercase letters', () => {
|
|
2764
|
+
const workspaceRoot = createWorkspace('structured-rule-uppercase-title', {
|
|
2765
|
+
'.xdrs/index.md': rootIndex(),
|
|
2766
|
+
'.xdrs/_local/adrs/index.md': localAdrIndex([
|
|
2767
|
+
'- [001-main](principles/001-main.md) - Main decision'
|
|
2768
|
+
]),
|
|
2769
|
+
'.xdrs/_local/adrs/principles/001-main.md': xdrDocument([
|
|
2770
|
+
'### Details',
|
|
2771
|
+
'',
|
|
2772
|
+
'#### 01-code-MUST-be-linted',
|
|
2773
|
+
'',
|
|
2774
|
+
'This rule MUST be followed.',
|
|
2775
|
+
].join('\n')),
|
|
2776
|
+
});
|
|
2777
|
+
|
|
2778
|
+
const result = lintWorkspace(workspaceRoot);
|
|
2779
|
+
|
|
2780
|
+
expect(result.errors.join('\n')).toContain('structured rule title must be all lowercase');
|
|
2781
|
+
expect(result.errors.join('\n')).toContain('[_core-adr-policy-008.05-rule-title-must-be-all-lowercase]');
|
|
2782
|
+
});
|
|
2783
|
+
|
|
2784
|
+
test('reports structured rule body with bold marks around normative keyword', () => {
|
|
2785
|
+
const workspaceRoot = createWorkspace('structured-rule-bold-normative', {
|
|
2786
|
+
'.xdrs/index.md': rootIndex(),
|
|
2787
|
+
'.xdrs/_local/adrs/index.md': localAdrIndex([
|
|
2788
|
+
'- [001-main](principles/001-main.md) - Main decision'
|
|
2789
|
+
]),
|
|
2790
|
+
'.xdrs/_local/adrs/principles/001-main.md': xdrDocument([
|
|
2791
|
+
'### Details',
|
|
2792
|
+
'',
|
|
2793
|
+
'#### 01-my-rule',
|
|
2794
|
+
'',
|
|
2795
|
+
'This rule **MUST** be followed.',
|
|
2796
|
+
].join('\n')),
|
|
2797
|
+
});
|
|
2798
|
+
|
|
2799
|
+
const result = lintWorkspace(workspaceRoot);
|
|
2800
|
+
|
|
2801
|
+
expect(result.errors.join('\n')).toContain('must not use bold or italic marks around normative keywords');
|
|
2802
|
+
expect(result.errors.join('\n')).toContain('[_core-adr-policy-008.06-normative-keywords-must-not-use-emphasis-marks]');
|
|
2803
|
+
});
|
|
2804
|
+
|
|
2805
|
+
test('reports structured rule body with italic marks around normative keyword', () => {
|
|
2806
|
+
const workspaceRoot = createWorkspace('structured-rule-italic-normative', {
|
|
2807
|
+
'.xdrs/index.md': rootIndex(),
|
|
2808
|
+
'.xdrs/_local/adrs/index.md': localAdrIndex([
|
|
2809
|
+
'- [001-main](principles/001-main.md) - Main decision'
|
|
2810
|
+
]),
|
|
2811
|
+
'.xdrs/_local/adrs/principles/001-main.md': xdrDocument([
|
|
2812
|
+
'### Details',
|
|
2813
|
+
'',
|
|
2814
|
+
'#### 01-my-rule',
|
|
2815
|
+
'',
|
|
2816
|
+
'This rule _SHOULD_ be considered.',
|
|
2817
|
+
].join('\n')),
|
|
2818
|
+
});
|
|
2819
|
+
|
|
2820
|
+
const result = lintWorkspace(workspaceRoot);
|
|
2821
|
+
|
|
2822
|
+
expect(result.errors.join('\n')).toContain('must not use bold or italic marks around normative keywords');
|
|
2823
|
+
expect(result.errors.join('\n')).toContain('[_core-adr-policy-008.06-normative-keywords-must-not-use-emphasis-marks]');
|
|
2824
|
+
});
|
|
2825
|
+
|
|
2826
|
+
test('accepts normative keywords in plain text in structured rule body', () => {
|
|
2827
|
+
const workspaceRoot = createWorkspace('structured-rule-plain-normative', {
|
|
2828
|
+
'.xdrs/index.md': rootIndex(),
|
|
2829
|
+
'.xdrs/_local/adrs/index.md': localAdrIndex([
|
|
2830
|
+
'- [001-main](principles/001-main.md) - Main decision'
|
|
2831
|
+
]),
|
|
2832
|
+
'.xdrs/_local/adrs/principles/001-main.md': xdrDocument([
|
|
2833
|
+
'### Details',
|
|
2834
|
+
'',
|
|
2835
|
+
'#### 01-my-rule',
|
|
2836
|
+
'',
|
|
2837
|
+
'This rule MUST be followed and implementors SHOULD consider it carefully.',
|
|
2838
|
+
].join('\n')),
|
|
2839
|
+
});
|
|
2840
|
+
|
|
2841
|
+
const result = lintWorkspace(workspaceRoot);
|
|
2842
|
+
|
|
2843
|
+
expect(result.errors.join('\n')).not.toContain('bold or italic marks');
|
|
2844
|
+
});
|
|
2845
|
+
|
|
2736
2846
|
test('reports research section exceeding word limit', () => {
|
|
2737
2847
|
const body500words = Array(500).fill('word').join(' ');
|
|
2738
2848
|
const workspaceRoot = createWorkspace('research-section-over-limit', {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xdrs-core",
|
|
3
|
-
"version": "0.38.
|
|
3
|
+
"version": "0.38.4",
|
|
4
4
|
"description": "A framework to structure, compile and distribute Architectural (ADR), Business (BDR), and Engineering (EDR) decision records contents so that AI agents and humans can reliably find and use them with hierarchical scopes and controlled rollout in the format of distributable versioned packages.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: _core-adr-policy-008-policy-standards-structured
|
|
3
|
-
description: Extends policy-standards with a numbered rule format for Policy documents that define strong policies or rules, or need individually referenceable items. Use when a Policy must expose explicit rule blocks that other documents or skills may cite by identifier.
|
|
4
|
-
apply-to: Policy documents requiring structured rule blocks
|
|
5
|
-
valid-from: 2025-01-01
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# _core-adr-policy-008: Policy standards - structured
|
|
9
|
-
|
|
10
|
-
## Context and Problem Statement
|
|
11
|
-
|
|
12
|
-
Some Policy documents define multiple strong policies or rules that must be stated explicitly so they can be applied consistently. In other cases, documents, skills, or agents need to refer to one specific rule without copying its content. Without a standard format, prose references like "see the third bullet in Details" are fragile and ambiguous.
|
|
13
|
-
|
|
14
|
-
Question: How should a Policy document expose strong or individually referenceable rules or policies so they stay explicit, stable, and easy to cite?
|
|
15
|
-
|
|
16
|
-
## Decision Outcome
|
|
17
|
-
|
|
18
|
-
**Numbered rule blocks inside Details with a canonical citation syntax**
|
|
19
|
-
|
|
20
|
-
When a Policy document defines strong rules or policies that MUST be stated explicitly, or when documents and skills need to cite individual rules precisely, each rule MUST be placed inside `### Details` as a numbered heading block. Referencing documents and skills MUST cite rules using the canonical dot-notation identifier.
|
|
21
|
-
|
|
22
|
-
### Details
|
|
23
|
-
|
|
24
|
-
Use this format when the decision defines strong rules or policies that MUST be stated explicitly as stable rule blocks, or when there is a clear need for external documents, skills, or agents to reference specific items inside a Policy without duplicating the full policy text. Standard Policies that do not define strong rule sets and do not need item-level citation SHOULD follow `_core-adr-policy-002-policy-standards` without adding numbered rule headings.
|
|
25
|
-
|
|
26
|
-
#### Rule block format
|
|
27
|
-
|
|
28
|
-
Each numbered rule MUST be written as:
|
|
29
|
-
|
|
30
|
-
```markdown
|
|
31
|
-
#### [NN]-[short-rule-title-in-mandatory-advisory-language-in-kebab-case-<12-words]
|
|
32
|
-
[Body using mandatory or advisory language as defined in _core-adr-policy-001. State the requirement and the situations in which it MUST or SHOULD be followed. Under 500 words.]
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Where `NN` is a two-digit zero-padded sequence number (e.g. `01`, `02`, `12`). Numbers MUST be unique within the document and MUST NOT be reused after a rule is removed. The short descriptive title MUST be in kebab-case (lowercase words separated by hyphens, no spaces or uppercase letters) and express the rule summary contents (e.g.: "43-code-must-be-linted", "12-use-standard-file-structure", "02-log-all-errors-to-mlflow")
|
|
36
|
-
|
|
37
|
-
Rule bodies MUST use the mandatory or advisory language terms defined in `_core-adr-policy-001`:
|
|
38
|
-
|
|
39
|
-
- Mandatory: "must", "always", "never", "required", "mandatory"
|
|
40
|
-
- Advisory: "should", "recommended", "advised", "preferably", "possibly", "optionally"
|
|
41
|
-
|
|
42
|
-
#### Citation syntax
|
|
43
|
-
|
|
44
|
-
When another document or skill cites a specific rule, it MUST use the following dot-notation:
|
|
45
|
-
|
|
46
|
-
```
|
|
47
|
-
policy-name.NN-short-rule-title-in-kebab-case
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Examples:
|
|
51
|
-
|
|
52
|
-
- `_core-adr-policy-008-policy-standards-structured.01-always-use-numbered-rules-for-strong-or-referenceable-policies`
|
|
53
|
-
- `_local-bdr-policy-003-data-retention-policy.02-purge-schedule-for-pii`
|
|
54
|
-
|
|
55
|
-
The `policy-name` MUST match the `name` field in the frontmatter of the source document exactly. The rule identifier after the dot MUST match the heading text exactly, including the two-digit prefix.
|
|
56
|
-
|
|
57
|
-
#### 01-always-use-numbered-rules-for-strong-or-referenceable-policies
|
|
58
|
-
|
|
59
|
-
Numbered rule blocks MUST be added to a Policy when the decision defines strong rules or policies that MUST be stated explicitly as stable items, or when there is a clear need for other documents, skills, or agents to cite individual rules by identifier. Adding numbered rules only for cosmetic organization SHOULD NOT be done. Standard Policy documents that do not define strong rule sets and are not expected to be cited at the rule level SHOULD follow `_core-adr-policy-002-policy-standards` without this structured format.
|
|
60
|
-
|
|
61
|
-
#### 02-rule-numbering-must-be-stable
|
|
62
|
-
|
|
63
|
-
Rule numbers MUST NOT be reused within the same document. When a rule is removed, its number becomes permanently retired for that document. Gaps in the sequence are expected and MUST NOT be filled by renumbering remaining rules, as existing citations depend on number stability.
|
|
64
|
-
|
|
65
|
-
#### 03-rule-body-must-use-normative-language
|
|
66
|
-
|
|
67
|
-
Every rule body MUST contain at least one mandatory or advisory language term as defined in `_core-adr-policy-001`. Rule bodies without normative language MUST NOT be published, as they fail to communicate whether compliance is required or recommended.
|
|
68
|
-
|
|
69
|
-
#### 04-citations-must-use-exact-identifiers
|
|
70
|
-
|
|
71
|
-
Documents and skills that cite a rule MUST use the exact dot-notation form: `policy-name.NN-short-rule-title-in-kebab-case`. Prose paraphrases such as "see rule 3" or "the third rule in that Policy" MUST NOT be used as citations, because they are ambiguous and break when rules are reordered or reworded.
|
|
72
|
-
|
|
73
|
-
## Considered Options
|
|
74
|
-
|
|
75
|
-
* (REJECTED) **Free-form prose rules with section anchors** — Use markdown heading anchors as citation targets.
|
|
76
|
-
* Reason: Anchors are fragile across editors, rendering tools, and refactors. They do not enforce a stable numbering contract and break silently when headings are reworded.
|
|
77
|
-
* (CHOSEN) **Numbered rule blocks inside Details** — Prefix each rule heading with a two-digit sequence number and use dot-notation for citations.
|
|
78
|
-
* Reason: Minimal addition to the existing Policy template, stable identifiers independent of heading text, and fully compatible with `_core-adr-policy-002-policy-standards`.
|
|
79
|
-
|
|
80
|
-
## References
|
|
81
|
-
|
|
82
|
-
- [_core-adr-policy-001 - XDRS core](001-xdrs-core.md)
|
|
83
|
-
- [_core-adr-policy-002 - Policy standards](002-policy-standards.md)
|