@mytechtoday/augment-extensions 1.2.2 → 1.3.1
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/LICENSE +22 -22
- package/augment-extensions/domain-rules/software-architecture/README.md +143 -143
- package/augment-extensions/domain-rules/software-architecture/examples/banking-layered.md +961 -961
- package/augment-extensions/domain-rules/software-architecture/examples/ecommerce-microservices.md +990 -990
- package/augment-extensions/domain-rules/software-architecture/examples/iot-eventdriven.md +882 -882
- package/augment-extensions/domain-rules/software-architecture/examples/monolith-to-microservices-migration.md +703 -703
- package/augment-extensions/domain-rules/software-architecture/examples/serverless-imageprocessing.md +957 -957
- package/augment-extensions/domain-rules/software-architecture/examples/trading-eventdriven.md +747 -747
- package/augment-extensions/domain-rules/software-architecture/module.json +119 -119
- package/augment-extensions/domain-rules/software-architecture/rules/challenges-solutions.md +763 -763
- package/augment-extensions/domain-rules/software-architecture/rules/definitions-terminology.md +409 -409
- package/augment-extensions/domain-rules/software-architecture/rules/design-principles.md +684 -684
- package/augment-extensions/domain-rules/software-architecture/rules/evaluation-testing.md +1381 -1381
- package/augment-extensions/domain-rules/software-architecture/rules/event-driven-architecture.md +616 -616
- package/augment-extensions/domain-rules/software-architecture/rules/fundamentals.md +306 -306
- package/augment-extensions/domain-rules/software-architecture/rules/industry-architectures.md +554 -554
- package/augment-extensions/domain-rules/software-architecture/rules/layered-architecture.md +776 -776
- package/augment-extensions/domain-rules/software-architecture/rules/microservices-architecture.md +503 -503
- package/augment-extensions/domain-rules/software-architecture/rules/modeling-documentation.md +1199 -1199
- package/augment-extensions/domain-rules/software-architecture/rules/monolithic-architecture.md +351 -351
- package/augment-extensions/domain-rules/software-architecture/rules/principles.md +556 -556
- package/augment-extensions/domain-rules/software-architecture/rules/quality-attributes.md +797 -797
- package/augment-extensions/domain-rules/software-architecture/rules/scalability-performance.md +1345 -1345
- package/augment-extensions/domain-rules/software-architecture/rules/security-architecture.md +1039 -1039
- package/augment-extensions/domain-rules/software-architecture/rules/serverless-architecture.md +711 -711
- package/augment-extensions/domain-rules/software-architecture/rules/skills-development.md +568 -568
- package/augment-extensions/domain-rules/software-architecture/rules/tools-methodologies.md +961 -961
- package/augment-extensions/visual-design/CHANGELOG.md +132 -0
- package/augment-extensions/visual-design/README.md +255 -0
- package/augment-extensions/visual-design/__tests__/README.md +119 -0
- package/augment-extensions/visual-design/__tests__/style-selector.test.ts +172 -0
- package/augment-extensions/visual-design/__tests__/vendor-styles.test.ts +214 -0
- package/augment-extensions/visual-design/domains/other/ai-prompt-helper.ts +157 -0
- package/augment-extensions/visual-design/domains/other/dotnet-application.ts +156 -0
- package/augment-extensions/visual-design/domains/other/linux-platform.ts +156 -0
- package/augment-extensions/visual-design/domains/other/mobile-application.ts +157 -0
- package/augment-extensions/visual-design/domains/other/motion-picture.ts +156 -0
- package/augment-extensions/visual-design/domains/other/os-application.ts +156 -0
- package/augment-extensions/visual-design/domains/other/print-campaigns.ts +158 -0
- package/augment-extensions/visual-design/domains/other/web-app.ts +157 -0
- package/augment-extensions/visual-design/domains/other/website.ts +161 -0
- package/augment-extensions/visual-design/domains/other/windows-platform.ts +156 -0
- package/augment-extensions/visual-design/domains/web-page-styles/amazon-cloudscape.ts +506 -0
- package/augment-extensions/visual-design/domains/web-page-styles/google-modern.ts +615 -0
- package/augment-extensions/visual-design/domains/web-page-styles/microsoft-fluent.ts +531 -0
- package/augment-extensions/visual-design/examples/README.md +97 -0
- package/augment-extensions/visual-design/examples/ai-prompt-generation.md +233 -0
- package/augment-extensions/visual-design/examples/basic-usage.md +216 -0
- package/augment-extensions/visual-design/examples/domain-workflows.md +257 -0
- package/augment-extensions/visual-design/examples/vendor-comparison.md +247 -0
- package/augment-extensions/visual-design/module.json +78 -0
- package/augment-extensions/visual-design/style-selector.ts +177 -0
- package/augment-extensions/visual-design/types.ts +302 -0
- package/augment-extensions/visual-design/visual-design-core.ts +469 -0
- package/augment-extensions/workflows/adr-support/README.md +227 -0
- package/augment-extensions/workflows/adr-support/__tests__/adr-validator.test.ts +203 -0
- package/augment-extensions/workflows/adr-support/adr-validator.ts +162 -0
- package/augment-extensions/workflows/adr-support/examples/complete-lifecycle-example.md +449 -0
- package/augment-extensions/workflows/adr-support/examples/integration-example.md +580 -0
- package/augment-extensions/workflows/adr-support/examples/superseding-example.md +436 -0
- package/augment-extensions/workflows/adr-support/module.json +112 -0
- package/augment-extensions/workflows/adr-support/rules/adr-creation.md +372 -0
- package/augment-extensions/workflows/adr-support/rules/beads-integration.md +443 -0
- package/augment-extensions/workflows/adr-support/rules/conflict-detection.md +486 -0
- package/augment-extensions/workflows/adr-support/rules/decision-detection.md +362 -0
- package/augment-extensions/workflows/adr-support/rules/lifecycle-management.md +427 -0
- package/augment-extensions/workflows/adr-support/rules/openspec-integration.md +465 -0
- package/augment-extensions/workflows/adr-support/rules/template-selection.md +405 -0
- package/augment-extensions/workflows/adr-support/rules/validation-rules.md +543 -0
- package/augment-extensions/workflows/adr-support/schemas/adr-config.json +191 -0
- package/augment-extensions/workflows/adr-support/schemas/adr-metadata.json +172 -0
- package/augment-extensions/workflows/adr-support/templates/business-case.md +235 -0
- package/augment-extensions/workflows/adr-support/templates/madr-elaborate.md +197 -0
- package/augment-extensions/workflows/adr-support/templates/madr-simple.md +68 -0
- package/augment-extensions/workflows/adr-support/templates/nygard.md +84 -0
- package/augment-extensions/writing-standards/screenplay/rules/file-organization.md +213 -213
- package/augment-extensions/writing-standards/screenplay/utils/__tests__/file-organization.test.ts +169 -169
- package/augment-extensions/writing-standards/screenplay/utils/file-organization.ts +165 -165
- package/cli/dist/utils/auto-sync.js +19 -19
- package/package.json +5 -3
- package/augment-extensions/workflows/openspec/README.md +0 -96
- package/augment-extensions/workflows/openspec/examples/complete-change-example.md +0 -244
- package/augment-extensions/workflows/openspec/module.json +0 -54
- package/augment-extensions/workflows/openspec/rules/best-practices.md +0 -272
- package/augment-extensions/workflows/openspec/rules/manual-setup.md +0 -231
- package/augment-extensions/workflows/openspec/rules/spec-format.md +0 -236
- package/augment-extensions/workflows/openspec/rules/workflow.md +0 -214
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
# ADR Validation Rules
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This document defines validation and completeness checks for Architecture Decision Records (ADRs). These rules ensure ADRs are well-formed, complete, and useful for their intended purpose.
|
|
6
|
+
|
|
7
|
+
## Validation Levels
|
|
8
|
+
|
|
9
|
+
### Level 1: Structural Validation (Required)
|
|
10
|
+
|
|
11
|
+
Must pass before ADR can be created or status changed.
|
|
12
|
+
|
|
13
|
+
### Level 2: Content Validation (Warning)
|
|
14
|
+
|
|
15
|
+
Should pass for quality, but won't block creation.
|
|
16
|
+
|
|
17
|
+
### Level 3: Reference Validation (Warning)
|
|
18
|
+
|
|
19
|
+
Validates links and references, warns if broken.
|
|
20
|
+
|
|
21
|
+
## Structural Validation Rules
|
|
22
|
+
|
|
23
|
+
### Metadata Validation
|
|
24
|
+
|
|
25
|
+
#### Required Fields
|
|
26
|
+
|
|
27
|
+
**Rule:** All required metadata fields must be present and valid.
|
|
28
|
+
|
|
29
|
+
```yaml
|
|
30
|
+
---
|
|
31
|
+
id: adr-NNNN # Required: Format adr-NNNN
|
|
32
|
+
title: "Decision Title" # Required: 10-100 characters
|
|
33
|
+
status: proposed # Required: Valid status value
|
|
34
|
+
date: 2026-02-05 # Required: ISO 8601 format
|
|
35
|
+
deciders: ["person"] # Required: At least one decider
|
|
36
|
+
---
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Validation Checks:**
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
function validateMetadata(adr: ADR): ValidationResult {
|
|
43
|
+
const errors = [];
|
|
44
|
+
|
|
45
|
+
// ID validation
|
|
46
|
+
if (!adr.id) {
|
|
47
|
+
errors.push("Missing required field: id");
|
|
48
|
+
} else if (!/^adr-\d{4}$/.test(adr.id)) {
|
|
49
|
+
errors.push("Invalid ID format. Must be adr-NNNN (e.g., adr-0001)");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Title validation
|
|
53
|
+
if (!adr.title) {
|
|
54
|
+
errors.push("Missing required field: title");
|
|
55
|
+
} else if (adr.title.length < 10 || adr.title.length > 100) {
|
|
56
|
+
errors.push("Title must be 10-100 characters");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Status validation
|
|
60
|
+
const validStatuses = ['draft', 'proposed', 'approved', 'implemented', 'maintained', 'superseded', 'sunset'];
|
|
61
|
+
if (!adr.status) {
|
|
62
|
+
errors.push("Missing required field: status");
|
|
63
|
+
} else if (!validStatuses.includes(adr.status)) {
|
|
64
|
+
errors.push(`Invalid status. Must be one of: ${validStatuses.join(', ')}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Date validation
|
|
68
|
+
if (!adr.date) {
|
|
69
|
+
errors.push("Missing required field: date");
|
|
70
|
+
} else if (!isValidISO8601(adr.date)) {
|
|
71
|
+
errors.push("Invalid date format. Must be ISO 8601 (YYYY-MM-DD)");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Deciders validation
|
|
75
|
+
if (!adr.deciders || adr.deciders.length === 0) {
|
|
76
|
+
errors.push("At least one decider must be specified");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return { valid: errors.length === 0, errors };
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
#### Optional Fields Validation
|
|
84
|
+
|
|
85
|
+
**Rule:** Optional fields, if present, must be valid.
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
function validateOptionalFields(adr: ADR): ValidationResult {
|
|
89
|
+
const warnings = [];
|
|
90
|
+
|
|
91
|
+
// Tags validation
|
|
92
|
+
if (adr.tags && !Array.isArray(adr.tags)) {
|
|
93
|
+
warnings.push("Tags must be an array");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Supersedes validation
|
|
97
|
+
if (adr.supersedes) {
|
|
98
|
+
if (!Array.isArray(adr.supersedes)) {
|
|
99
|
+
warnings.push("Supersedes must be an array");
|
|
100
|
+
} else {
|
|
101
|
+
adr.supersedes.forEach(id => {
|
|
102
|
+
if (!/^adr-\d{4}$/.test(id)) {
|
|
103
|
+
warnings.push(`Invalid ADR ID in supersedes: ${id}`);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Superseded_by validation
|
|
110
|
+
if (adr.superseded_by && !/^adr-\d{4}$/.test(adr.superseded_by)) {
|
|
111
|
+
warnings.push(`Invalid ADR ID in superseded_by: ${adr.superseded_by}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return { valid: warnings.length === 0, warnings };
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### File Naming Validation
|
|
119
|
+
|
|
120
|
+
**Rule:** ADR files must follow naming convention.
|
|
121
|
+
|
|
122
|
+
**Format:** `adr/NNNN-brief-title.md`
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
function validateFileName(filePath: string): ValidationResult {
|
|
126
|
+
const errors = [];
|
|
127
|
+
const pattern = /^adr\/\d{4}-[a-z0-9-]+\.md$/;
|
|
128
|
+
|
|
129
|
+
if (!pattern.test(filePath)) {
|
|
130
|
+
errors.push("Invalid file name. Must be adr/NNNN-brief-title.md");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Extract number from filename
|
|
134
|
+
const match = filePath.match(/^adr\/(\d{4})-/);
|
|
135
|
+
if (match) {
|
|
136
|
+
const fileNumber = match[1];
|
|
137
|
+
// Should match ID in metadata
|
|
138
|
+
// (checked in cross-validation)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return { valid: errors.length === 0, errors };
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Content Validation Rules
|
|
146
|
+
|
|
147
|
+
### Required Sections
|
|
148
|
+
|
|
149
|
+
**Rule:** ADRs must contain required sections based on template.
|
|
150
|
+
|
|
151
|
+
#### Nygard Template Requirements
|
|
152
|
+
|
|
153
|
+
```markdown
|
|
154
|
+
# Title
|
|
155
|
+
|
|
156
|
+
## Status
|
|
157
|
+
[Must be present and match metadata]
|
|
158
|
+
|
|
159
|
+
## Context
|
|
160
|
+
[Must be present and non-empty]
|
|
161
|
+
|
|
162
|
+
## Decision
|
|
163
|
+
[Must be present and non-empty]
|
|
164
|
+
|
|
165
|
+
## Consequences
|
|
166
|
+
[Must be present and non-empty]
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Validation:**
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
function validateNygardContent(content: string): ValidationResult {
|
|
173
|
+
const warnings = [];
|
|
174
|
+
|
|
175
|
+
if (!content.includes('## Status')) {
|
|
176
|
+
warnings.push("Missing required section: Status");
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (!content.includes('## Context')) {
|
|
180
|
+
warnings.push("Missing required section: Context");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (!content.includes('## Decision')) {
|
|
184
|
+
warnings.push("Missing required section: Decision");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (!content.includes('## Consequences')) {
|
|
188
|
+
warnings.push("Missing required section: Consequences");
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return { valid: warnings.length === 0, warnings };
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
#### MADR Template Requirements
|
|
196
|
+
|
|
197
|
+
```markdown
|
|
198
|
+
# Title
|
|
199
|
+
|
|
200
|
+
## Context and Problem Statement
|
|
201
|
+
[Must be present and non-empty]
|
|
202
|
+
|
|
203
|
+
## Decision Drivers
|
|
204
|
+
[Must be present with at least one driver]
|
|
205
|
+
|
|
206
|
+
## Considered Options
|
|
207
|
+
[Must be present with at least one option]
|
|
208
|
+
|
|
209
|
+
## Decision Outcome
|
|
210
|
+
[Must be present and non-empty]
|
|
211
|
+
|
|
212
|
+
## Consequences
|
|
213
|
+
[Must be present and non-empty]
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Content Quality Checks
|
|
217
|
+
|
|
218
|
+
**Rule:** Content should be meaningful, not placeholder text.
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
function validateContentQuality(content: string): ValidationResult {
|
|
222
|
+
const warnings = [];
|
|
223
|
+
|
|
224
|
+
// Check for placeholder text
|
|
225
|
+
const placeholders = ['TODO', 'TBD', 'FIXME', 'XXX', '[Insert', 'Lorem ipsum'];
|
|
226
|
+
placeholders.forEach(placeholder => {
|
|
227
|
+
if (content.includes(placeholder)) {
|
|
228
|
+
warnings.push(`Contains placeholder text: ${placeholder}`);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Check for minimum content length
|
|
233
|
+
const sections = extractSections(content);
|
|
234
|
+
Object.entries(sections).forEach(([section, text]) => {
|
|
235
|
+
if (text.trim().length < 50) {
|
|
236
|
+
warnings.push(`Section "${section}" is too brief (< 50 characters)`);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
return { valid: warnings.length === 0, warnings };
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Context Section Validation
|
|
245
|
+
|
|
246
|
+
**Rule:** Context should explain "why" not "how".
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
function validateContext(context: string): ValidationResult {
|
|
250
|
+
const warnings = [];
|
|
251
|
+
|
|
252
|
+
// Should contain problem statement
|
|
253
|
+
const problemIndicators = ['problem', 'issue', 'challenge', 'need', 'requirement'];
|
|
254
|
+
const hasProblem = problemIndicators.some(word =>
|
|
255
|
+
context.toLowerCase().includes(word)
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
if (!hasProblem) {
|
|
259
|
+
warnings.push("Context should clearly state the problem or need");
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Should not be too implementation-focused
|
|
263
|
+
const implDetails = ['function', 'class', 'variable', 'line', 'file'];
|
|
264
|
+
const tooDetailed = implDetails.filter(word =>
|
|
265
|
+
context.toLowerCase().includes(word)
|
|
266
|
+
).length > 2;
|
|
267
|
+
|
|
268
|
+
if (tooDetailed) {
|
|
269
|
+
warnings.push("Context contains too many implementation details. Focus on 'why' not 'how'");
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return { valid: warnings.length === 0, warnings };
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Decision Section Validation
|
|
277
|
+
|
|
278
|
+
**Rule:** Decision should clearly state what is being done.
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
function validateDecision(decision: string): ValidationResult {
|
|
282
|
+
const warnings = [];
|
|
283
|
+
|
|
284
|
+
// Should contain action verbs
|
|
285
|
+
const actionVerbs = ['will', 'use', 'adopt', 'implement', 'migrate', 'choose', 'select'];
|
|
286
|
+
const hasAction = actionVerbs.some(verb =>
|
|
287
|
+
decision.toLowerCase().includes(verb)
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
if (!hasAction) {
|
|
291
|
+
warnings.push("Decision should clearly state what action is being taken");
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Should not be a question
|
|
295
|
+
if (decision.includes('?')) {
|
|
296
|
+
warnings.push("Decision should be a statement, not a question");
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return { valid: warnings.length === 0, warnings };
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Consequences Section Validation
|
|
304
|
+
|
|
305
|
+
**Rule:** Consequences should cover both positive and negative outcomes.
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
function validateConsequences(consequences: string): ValidationResult {
|
|
309
|
+
const warnings = [];
|
|
310
|
+
|
|
311
|
+
// Should have positive consequences
|
|
312
|
+
const positiveIndicators = ['benefit', 'advantage', 'pro', 'positive', 'improve'];
|
|
313
|
+
const hasPositive = positiveIndicators.some(word =>
|
|
314
|
+
consequences.toLowerCase().includes(word)
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
// Should have negative consequences
|
|
318
|
+
const negativeIndicators = ['cost', 'risk', 'con', 'negative', 'trade-off', 'challenge'];
|
|
319
|
+
const hasNegative = negativeIndicators.some(word =>
|
|
320
|
+
consequences.toLowerCase().includes(word)
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
if (!hasPositive) {
|
|
324
|
+
warnings.push("Consequences should include positive outcomes");
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (!hasNegative) {
|
|
328
|
+
warnings.push("Consequences should include negative outcomes or trade-offs");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return { valid: warnings.length === 0, warnings };
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## Reference Validation Rules
|
|
336
|
+
|
|
337
|
+
### ADR Reference Validation
|
|
338
|
+
|
|
339
|
+
**Rule:** Referenced ADRs must exist.
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
function validateADRReferences(adr: ADR, allADRs: ADR[]): ValidationResult {
|
|
343
|
+
const warnings = [];
|
|
344
|
+
const adrIds = new Set(allADRs.map(a => a.id));
|
|
345
|
+
|
|
346
|
+
// Validate supersedes references
|
|
347
|
+
if (adr.supersedes) {
|
|
348
|
+
adr.supersedes.forEach(id => {
|
|
349
|
+
if (!adrIds.has(id)) {
|
|
350
|
+
warnings.push(`Referenced ADR does not exist: ${id}`);
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Validate superseded_by reference
|
|
356
|
+
if (adr.superseded_by && !adrIds.has(adr.superseded_by)) {
|
|
357
|
+
warnings.push(`Referenced ADR does not exist: ${adr.superseded_by}`);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Validate related_decisions
|
|
361
|
+
if (adr.related_decisions) {
|
|
362
|
+
adr.related_decisions.forEach(id => {
|
|
363
|
+
if (!adrIds.has(id)) {
|
|
364
|
+
warnings.push(`Related ADR does not exist: ${id}`);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return { valid: warnings.length === 0, warnings };
|
|
370
|
+
}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Spec Reference Validation
|
|
374
|
+
|
|
375
|
+
**Rule:** Referenced specs should exist.
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
function validateSpecReferences(adr: ADR): ValidationResult {
|
|
379
|
+
const warnings = [];
|
|
380
|
+
|
|
381
|
+
if (adr.related_specs) {
|
|
382
|
+
adr.related_specs.forEach(specPath => {
|
|
383
|
+
if (!fileExists(specPath)) {
|
|
384
|
+
warnings.push(`Referenced spec does not exist: ${specPath}`);
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return { valid: warnings.length === 0, warnings };
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Task Reference Validation
|
|
394
|
+
|
|
395
|
+
**Rule:** Referenced tasks should exist.
|
|
396
|
+
|
|
397
|
+
```typescript
|
|
398
|
+
function validateTaskReferences(adr: ADR): ValidationResult {
|
|
399
|
+
const warnings = [];
|
|
400
|
+
|
|
401
|
+
if (adr.related_tasks) {
|
|
402
|
+
adr.related_tasks.forEach(taskId => {
|
|
403
|
+
if (!taskExists(taskId)) {
|
|
404
|
+
warnings.push(`Referenced task does not exist: ${taskId}`);
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return { valid: warnings.length === 0, warnings };
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
## Status Transition Validation
|
|
414
|
+
|
|
415
|
+
**Rule:** Status transitions must be valid.
|
|
416
|
+
|
|
417
|
+
See [Lifecycle Management](./lifecycle-management.md) for detailed transition rules.
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
function validateStatusTransition(currentStatus: string, newStatus: string): ValidationResult {
|
|
421
|
+
const validTransitions = {
|
|
422
|
+
'draft': ['proposed'],
|
|
423
|
+
'proposed': ['approved', 'draft'],
|
|
424
|
+
'approved': ['implemented', 'proposed'],
|
|
425
|
+
'implemented': ['maintained', 'superseded'],
|
|
426
|
+
'maintained': ['superseded', 'sunset'],
|
|
427
|
+
'superseded': [],
|
|
428
|
+
'sunset': []
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
const errors = [];
|
|
432
|
+
const allowed = validTransitions[currentStatus] || [];
|
|
433
|
+
|
|
434
|
+
if (!allowed.includes(newStatus)) {
|
|
435
|
+
errors.push(`Invalid transition from ${currentStatus} to ${newStatus}`);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
return { valid: errors.length === 0, errors };
|
|
439
|
+
}
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
## Completeness Criteria
|
|
443
|
+
|
|
444
|
+
### Draft Completeness
|
|
445
|
+
|
|
446
|
+
**Minimum requirements for draft status:**
|
|
447
|
+
- [ ] Valid metadata
|
|
448
|
+
- [ ] Title present
|
|
449
|
+
- [ ] At least one section started
|
|
450
|
+
|
|
451
|
+
### Proposed Completeness
|
|
452
|
+
|
|
453
|
+
**Requirements for proposed status:**
|
|
454
|
+
- [ ] All required sections present
|
|
455
|
+
- [ ] Context explains problem
|
|
456
|
+
- [ ] Decision stated clearly
|
|
457
|
+
- [ ] Consequences documented
|
|
458
|
+
- [ ] No placeholder text
|
|
459
|
+
- [ ] Reviewers identified
|
|
460
|
+
|
|
461
|
+
### Approved Completeness
|
|
462
|
+
|
|
463
|
+
**Requirements for approved status:**
|
|
464
|
+
- [ ] All proposed requirements met
|
|
465
|
+
- [ ] Approvers documented
|
|
466
|
+
- [ ] Approval date recorded
|
|
467
|
+
- [ ] Implementation tasks created (if applicable)
|
|
468
|
+
|
|
469
|
+
### Implemented Completeness
|
|
470
|
+
|
|
471
|
+
**Requirements for implemented status:**
|
|
472
|
+
- [ ] All approved requirements met
|
|
473
|
+
- [ ] Implementation date recorded
|
|
474
|
+
- [ ] Implementation notes added
|
|
475
|
+
- [ ] Related tasks completed
|
|
476
|
+
|
|
477
|
+
## Validation Workflow
|
|
478
|
+
|
|
479
|
+
### Pre-Creation Validation
|
|
480
|
+
|
|
481
|
+
```
|
|
482
|
+
User creates ADR
|
|
483
|
+
↓
|
|
484
|
+
Validate metadata (Level 1)
|
|
485
|
+
├─ Fail → Show errors, block creation
|
|
486
|
+
└─ Pass → Continue
|
|
487
|
+
↓
|
|
488
|
+
Validate content (Level 2)
|
|
489
|
+
├─ Warnings → Show warnings, allow creation
|
|
490
|
+
└─ Pass → Continue
|
|
491
|
+
↓
|
|
492
|
+
Create ADR file
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### Pre-Status-Change Validation
|
|
496
|
+
|
|
497
|
+
```
|
|
498
|
+
User changes status
|
|
499
|
+
↓
|
|
500
|
+
Validate transition (Level 1)
|
|
501
|
+
├─ Fail → Show errors, block change
|
|
502
|
+
└─ Pass → Continue
|
|
503
|
+
↓
|
|
504
|
+
Validate completeness (Level 2)
|
|
505
|
+
├─ Warnings → Show warnings, allow change
|
|
506
|
+
└─ Pass → Continue
|
|
507
|
+
↓
|
|
508
|
+
Update status
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
## Best Practices
|
|
512
|
+
|
|
513
|
+
1. **Validate Early**
|
|
514
|
+
- Check metadata before content
|
|
515
|
+
- Fail fast on structural issues
|
|
516
|
+
- Provide clear error messages
|
|
517
|
+
|
|
518
|
+
2. **Warn, Don't Block (for quality)**
|
|
519
|
+
- Content quality is subjective
|
|
520
|
+
- Allow user override
|
|
521
|
+
- Educate through warnings
|
|
522
|
+
|
|
523
|
+
3. **Validate References Lazily**
|
|
524
|
+
- Don't block on broken references
|
|
525
|
+
- Warn and allow fixing later
|
|
526
|
+
- Provide tools to find broken links
|
|
527
|
+
|
|
528
|
+
4. **Provide Helpful Messages**
|
|
529
|
+
- Explain what's wrong
|
|
530
|
+
- Suggest how to fix
|
|
531
|
+
- Link to documentation
|
|
532
|
+
|
|
533
|
+
5. **Support Incremental Improvement**
|
|
534
|
+
- Allow draft ADRs to be incomplete
|
|
535
|
+
- Enforce completeness at status transitions
|
|
536
|
+
- Enable iterative refinement
|
|
537
|
+
|
|
538
|
+
## See Also
|
|
539
|
+
|
|
540
|
+
- [ADR Creation Guidelines](./adr-creation.md)
|
|
541
|
+
- [Lifecycle Management](./lifecycle-management.md)
|
|
542
|
+
- [Template Selection](./template-selection.md)
|
|
543
|
+
|