@eddacraft/anvil-aps 0.1.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.
- package/AGENTS.md +155 -0
- package/LICENSE +14 -0
- package/README.md +57 -0
- package/TODO.md +40 -0
- package/dist/filter/context-bundle.d.ts +81 -0
- package/dist/filter/context-bundle.d.ts.map +1 -0
- package/dist/filter/context-bundle.js +230 -0
- package/dist/filter/index.d.ts +85 -0
- package/dist/filter/index.d.ts.map +1 -0
- package/dist/filter/index.js +169 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/loader/index.d.ts +80 -0
- package/dist/loader/index.d.ts.map +1 -0
- package/dist/loader/index.js +253 -0
- package/dist/parser/index.d.ts +24 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +22 -0
- package/dist/parser/parse-document.d.ts +17 -0
- package/dist/parser/parse-document.d.ts.map +1 -0
- package/dist/parser/parse-document.js +219 -0
- package/dist/parser/parse-index.d.ts +31 -0
- package/dist/parser/parse-index.d.ts.map +1 -0
- package/dist/parser/parse-index.js +251 -0
- package/dist/parser/parse-task.d.ts +30 -0
- package/dist/parser/parse-task.d.ts.map +1 -0
- package/dist/parser/parse-task.js +261 -0
- package/dist/state/index.d.ts +307 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +689 -0
- package/dist/templates/generator.d.ts +71 -0
- package/dist/templates/generator.d.ts.map +1 -0
- package/dist/templates/generator.js +723 -0
- package/dist/templates/index.d.ts +5 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +4 -0
- package/dist/types/index.d.ts +131 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +107 -0
- package/dist/validator/index.d.ts +83 -0
- package/dist/validator/index.d.ts.map +1 -0
- package/dist/validator/index.js +611 -0
- package/docs/APS-Anvil-Integration.md +750 -0
- package/docs/APS-Conventions.md +635 -0
- package/docs/APS-NonGoals.md +455 -0
- package/docs/APS-Planning-Spec-v0.1.md +362 -0
- package/examples/README.md +170 -0
- package/examples/feature-auth.aps.md +87 -0
- package/examples/refactor-error-handling.aps.md +119 -0
- package/examples/system-ecommerce/APS.md +57 -0
- package/examples/system-ecommerce/modules/auth.aps.md +38 -0
- package/examples/system-ecommerce/modules/cart.aps.md +53 -0
- package/examples/system-ecommerce/modules/payments.aps.md +68 -0
- package/examples/system-ecommerce/modules/products.aps.md +53 -0
- package/package.json +34 -0
- package/project.json +37 -0
- package/scripts/generate-templates.js +33 -0
- package/src/filter/context-bundle.ts +312 -0
- package/src/filter/filter.test.ts +317 -0
- package/src/filter/index.ts +249 -0
- package/src/index.ts +16 -0
- package/src/loader/index.ts +364 -0
- package/src/loader/loader.test.ts +224 -0
- package/src/parser/__fixtures__/invalid-task-id-not-padded.aps.md +7 -0
- package/src/parser/__fixtures__/invalid-task-id.aps.md +8 -0
- package/src/parser/__fixtures__/minimal-task.aps.md +7 -0
- package/src/parser/__fixtures__/non-scope-hyphenated.aps.md +10 -0
- package/src/parser/__fixtures__/simple-index.aps.md +35 -0
- package/src/parser/__fixtures__/simple-plan.aps.md +19 -0
- package/src/parser/index.ts +30 -0
- package/src/parser/parse-document.test.ts +603 -0
- package/src/parser/parse-document.ts +262 -0
- package/src/parser/parse-index.test.ts +316 -0
- package/src/parser/parse-index.ts +298 -0
- package/src/parser/parse-task.test.ts +476 -0
- package/src/parser/parse-task.ts +325 -0
- package/src/state/__fixtures__/invalid-plan.aps.md +9 -0
- package/src/state/__fixtures__/test-plan.aps.md +20 -0
- package/src/state/index.ts +879 -0
- package/src/state/state.test.ts +645 -0
- package/src/templates/generator.test.ts +378 -0
- package/src/templates/generator.ts +776 -0
- package/src/templates/index.ts +5 -0
- package/src/types/index.ts +168 -0
- package/src/validator/__fixtures__/broken-links.aps.md +10 -0
- package/src/validator/__fixtures__/circular-deps-index.aps.md +26 -0
- package/src/validator/__fixtures__/circular-modules/module-a.aps.md +9 -0
- package/src/validator/__fixtures__/circular-modules/module-b.aps.md +9 -0
- package/src/validator/__fixtures__/circular-modules/module-c.aps.md +9 -0
- package/src/validator/__fixtures__/dup-modules/module-a.aps.md +9 -0
- package/src/validator/__fixtures__/dup-modules/module-b.aps.md +9 -0
- package/src/validator/__fixtures__/duplicate-ids-index.aps.md +15 -0
- package/src/validator/__fixtures__/invalid-task-id.aps.md +17 -0
- package/src/validator/__fixtures__/missing-confidence.aps.md +9 -0
- package/src/validator/__fixtures__/missing-h1.aps.md +5 -0
- package/src/validator/__fixtures__/missing-intent.aps.md +9 -0
- package/src/validator/__fixtures__/missing-modules-section.aps.md +7 -0
- package/src/validator/__fixtures__/missing-tasks-section.aps.md +7 -0
- package/src/validator/__fixtures__/modules/auth.aps.md +17 -0
- package/src/validator/__fixtures__/modules/payments.aps.md +13 -0
- package/src/validator/__fixtures__/scope-mismatch.aps.md +14 -0
- package/src/validator/__fixtures__/valid-index.aps.md +24 -0
- package/src/validator/__fixtures__/valid-leaf.aps.md +22 -0
- package/src/validator/index.ts +776 -0
- package/src/validator/validator.test.ts +269 -0
- package/templates/index-full.md +94 -0
- package/templates/index-minimal.md +16 -0
- package/templates/index-template.md +63 -0
- package/templates/leaf-full.md +76 -0
- package/templates/leaf-minimal.md +14 -0
- package/templates/leaf-template.md +55 -0
- package/templates/simple-full.md +56 -0
- package/templates/simple-minimal.md +14 -0
- package/templates/simple-template.md +30 -0
- package/tsconfig.json +19 -0
- package/tsconfig.lib.json +14 -0
- package/tsconfig.lib.tsbuildinfo +1 -0
- package/tsconfig.spec.json +9 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vitest.config.ts +15 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validator module tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect } from 'vitest';
|
|
6
|
+
import { join, dirname } from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
import { validatePlanningDoc, formatValidationIssues, type ValidationResult } from './index.js';
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = dirname(__filename);
|
|
12
|
+
const fixturesDir = join(__dirname, '__fixtures__');
|
|
13
|
+
|
|
14
|
+
describe('validatePlanningDoc', () => {
|
|
15
|
+
describe('valid documents', () => {
|
|
16
|
+
it('should validate a valid leaf spec with no errors', async () => {
|
|
17
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'valid-leaf.aps.md'));
|
|
18
|
+
|
|
19
|
+
expect(result.valid).toBe(true);
|
|
20
|
+
expect(result.errors).toHaveLength(0);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should validate a valid index file with linked modules', async () => {
|
|
24
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'valid-index.aps.md'));
|
|
25
|
+
|
|
26
|
+
expect(result.valid).toBe(true);
|
|
27
|
+
expect(result.errors).toHaveLength(0);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('required-sections rule', () => {
|
|
32
|
+
it('should error when leaf spec is missing H1 title', async () => {
|
|
33
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'missing-h1.aps.md'));
|
|
34
|
+
|
|
35
|
+
expect(result.valid).toBe(false);
|
|
36
|
+
expect(result.errors.some((e) => e.rule === 'required-sections')).toBe(true);
|
|
37
|
+
expect(result.errors.some((e) => e.message.includes('H1 title'))).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should error when leaf spec is missing ## Tasks section', async () => {
|
|
41
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'missing-tasks-section.aps.md'));
|
|
42
|
+
|
|
43
|
+
expect(result.valid).toBe(false);
|
|
44
|
+
expect(result.errors.some((e) => e.rule === 'required-sections')).toBe(true);
|
|
45
|
+
expect(result.errors.some((e) => e.message.includes('## Tasks'))).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should error when index file is missing ## Modules section', async () => {
|
|
49
|
+
// This file doesn't have ## Modules, so it's treated as a leaf spec
|
|
50
|
+
// and will error because it's missing ## Tasks
|
|
51
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'missing-modules-section.aps.md'));
|
|
52
|
+
|
|
53
|
+
expect(result.valid).toBe(false);
|
|
54
|
+
expect(result.errors.some((e) => e.rule === 'required-sections')).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('task-format rule', () => {
|
|
59
|
+
it('should error when task heading has invalid format', async () => {
|
|
60
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'invalid-task-id.aps.md'));
|
|
61
|
+
|
|
62
|
+
expect(result.valid).toBe(false);
|
|
63
|
+
expect(result.errors.some((e) => e.rule === 'task-format')).toBe(true);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should error on lowercase task IDs', async () => {
|
|
67
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'invalid-task-id.aps.md'));
|
|
68
|
+
|
|
69
|
+
const formatErrors = result.errors.filter((e) => e.rule === 'task-format');
|
|
70
|
+
expect(formatErrors.some((e) => e.message.includes('test-001'))).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should error on task IDs with non-3-digit numbers', async () => {
|
|
74
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'invalid-task-id.aps.md'));
|
|
75
|
+
|
|
76
|
+
const formatErrors = result.errors.filter((e) => e.rule === 'task-format');
|
|
77
|
+
expect(formatErrors.some((e) => e.message.includes('T-1'))).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should error on task IDs with scope longer than 10 characters', async () => {
|
|
81
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'invalid-task-id.aps.md'));
|
|
82
|
+
|
|
83
|
+
const formatErrors = result.errors.filter((e) => e.rule === 'task-format');
|
|
84
|
+
expect(formatErrors.some((e) => e.message.includes('VERYLONGSCOPE123-001'))).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe('task-intent rule', () => {
|
|
89
|
+
it('should error when task is missing Intent field', async () => {
|
|
90
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'missing-intent.aps.md'));
|
|
91
|
+
|
|
92
|
+
expect(result.valid).toBe(false);
|
|
93
|
+
expect(result.errors.some((e) => e.rule === 'task-intent')).toBe(true);
|
|
94
|
+
expect(result.errors.some((e) => e.message.includes('Intent'))).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('missing-confidence rule (warning)', () => {
|
|
99
|
+
it('should warn when task is missing Confidence field', async () => {
|
|
100
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'missing-confidence.aps.md'));
|
|
101
|
+
|
|
102
|
+
// Should be valid (warnings don't invalidate)
|
|
103
|
+
expect(result.valid).toBe(true);
|
|
104
|
+
expect(result.warnings.some((w) => w.rule === 'missing-confidence')).toBe(true);
|
|
105
|
+
expect(result.warnings.some((w) => w.message.includes('Confidence'))).toBe(true);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('broken-links rule', () => {
|
|
110
|
+
it('should error when module link points to non-existent file', async () => {
|
|
111
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'broken-links.aps.md'));
|
|
112
|
+
|
|
113
|
+
expect(result.valid).toBe(false);
|
|
114
|
+
expect(result.errors.some((e) => e.rule === 'broken-links')).toBe(true);
|
|
115
|
+
expect(result.errors.some((e) => e.message.includes('nonexistent'))).toBe(true);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('duplicate-ids rule', () => {
|
|
120
|
+
it('should error when same task ID appears in multiple modules', async () => {
|
|
121
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'duplicate-ids-index.aps.md'));
|
|
122
|
+
|
|
123
|
+
expect(result.valid).toBe(false);
|
|
124
|
+
expect(result.errors.some((e) => e.rule === 'duplicate-ids')).toBe(true);
|
|
125
|
+
expect(result.errors.some((e) => e.message.includes('DUP-001'))).toBe(true);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe('circular-dependencies rule', () => {
|
|
130
|
+
it('should error when modules have circular dependencies', async () => {
|
|
131
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'circular-deps-index.aps.md'));
|
|
132
|
+
|
|
133
|
+
expect(result.valid).toBe(false);
|
|
134
|
+
expect(result.errors.some((e) => e.rule === 'circular-dependencies')).toBe(true);
|
|
135
|
+
expect(result.errors.some((e) => e.message.includes('Circular dependency'))).toBe(true);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe('scope-mismatch rule (warning)', () => {
|
|
140
|
+
it('should warn when task ID scope prefix does not match module scope', async () => {
|
|
141
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'scope-mismatch.aps.md'));
|
|
142
|
+
|
|
143
|
+
// Should be valid (warnings don't invalidate)
|
|
144
|
+
expect(result.valid).toBe(true);
|
|
145
|
+
expect(result.warnings.some((w) => w.rule === 'scope-mismatch')).toBe(true);
|
|
146
|
+
expect(result.warnings.some((w) => w.message.includes('AUTH-001'))).toBe(true);
|
|
147
|
+
expect(result.warnings.some((w) => w.message.includes('TEST'))).toBe(true);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should not warn when task ID scope prefix matches module scope', async () => {
|
|
151
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'scope-mismatch.aps.md'));
|
|
152
|
+
|
|
153
|
+
// TEST-001 should not generate a scope-mismatch warning
|
|
154
|
+
const testScopeWarnings = result.warnings.filter(
|
|
155
|
+
(w) => w.rule === 'scope-mismatch' && w.message.includes('TEST-001')
|
|
156
|
+
);
|
|
157
|
+
expect(testScopeWarnings).toHaveLength(0);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe('skipRules option', () => {
|
|
162
|
+
it('should skip specified rules', async () => {
|
|
163
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'missing-intent.aps.md'), {
|
|
164
|
+
skipRules: ['task-intent', 'missing-confidence'],
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
expect(result.errors.some((e) => e.rule === 'task-intent')).toBe(false);
|
|
168
|
+
expect(result.warnings.some((w) => w.rule === 'missing-confidence')).toBe(false);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
describe('recursive option', () => {
|
|
173
|
+
it('should not validate linked modules when recursive is false', async () => {
|
|
174
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'broken-links.aps.md'), {
|
|
175
|
+
recursive: false,
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// When not recursive, broken links are not checked
|
|
179
|
+
expect(result.errors.some((e) => e.rule === 'broken-links')).toBe(false);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
describe('file-readable rule', () => {
|
|
184
|
+
it('should error when file does not exist', async () => {
|
|
185
|
+
const result = await validatePlanningDoc('/nonexistent/path/file.aps.md');
|
|
186
|
+
|
|
187
|
+
expect(result.valid).toBe(false);
|
|
188
|
+
expect(result.errors.some((e) => e.rule === 'file-readable')).toBe(true);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
describe('formatValidationIssues', () => {
|
|
194
|
+
it('should format issues for display', async () => {
|
|
195
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'missing-intent.aps.md'));
|
|
196
|
+
const formatted = formatValidationIssues(result);
|
|
197
|
+
|
|
198
|
+
expect(formatted).toContain('[ERROR]');
|
|
199
|
+
expect(formatted).toContain('Intent');
|
|
200
|
+
expect(formatted).toContain('error(s)');
|
|
201
|
+
expect(formatted).toContain('warning(s)');
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should return "No issues found" for valid documents', async () => {
|
|
205
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'valid-leaf.aps.md'));
|
|
206
|
+
// Valid leaf spec might still have warnings (e.g., missing confidence)
|
|
207
|
+
// so we test the "no issues" case with a mock
|
|
208
|
+
expect(result.valid).toBe(true);
|
|
209
|
+
|
|
210
|
+
// Test the "no issues" case with a mock result
|
|
211
|
+
const mockResult: ValidationResult = {
|
|
212
|
+
valid: true,
|
|
213
|
+
issues: [],
|
|
214
|
+
errors: [],
|
|
215
|
+
warnings: [],
|
|
216
|
+
};
|
|
217
|
+
const mockFormatted = formatValidationIssues(mockResult);
|
|
218
|
+
expect(mockFormatted).toBe('No issues found.');
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('should include context in formatted output', async () => {
|
|
222
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'scope-mismatch.aps.md'));
|
|
223
|
+
const output = formatValidationIssues(result);
|
|
224
|
+
|
|
225
|
+
expect(output).toContain('Module scope:');
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('should include line numbers when available', async () => {
|
|
229
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'missing-intent.aps.md'));
|
|
230
|
+
const formatted = formatValidationIssues(result);
|
|
231
|
+
|
|
232
|
+
// Should contain file path with line number
|
|
233
|
+
expect(formatted).toMatch(/\.aps\.md:\d+/);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
describe('ValidationResult structure', () => {
|
|
238
|
+
it('should separate errors and warnings', async () => {
|
|
239
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'scope-mismatch.aps.md'));
|
|
240
|
+
|
|
241
|
+
expect(result.issues.length).toBe(result.errors.length + result.warnings.length);
|
|
242
|
+
expect(result.errors.every((e) => e.severity === 'error')).toBe(true);
|
|
243
|
+
expect(result.warnings.every((w) => w.severity === 'warning')).toBe(true);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('should mark as valid when only warnings exist', async () => {
|
|
247
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'missing-confidence.aps.md'));
|
|
248
|
+
|
|
249
|
+
expect(result.valid).toBe(true);
|
|
250
|
+
expect(result.warnings.length).toBeGreaterThan(0);
|
|
251
|
+
expect(result.errors).toHaveLength(0);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('should mark as invalid when errors exist', async () => {
|
|
255
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'missing-intent.aps.md'));
|
|
256
|
+
|
|
257
|
+
expect(result.valid).toBe(false);
|
|
258
|
+
expect(result.errors.length).toBeGreaterThan(0);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('should include path and lineNumber in issues where applicable', async () => {
|
|
262
|
+
const result = await validatePlanningDoc(join(fixturesDir, 'missing-intent.aps.md'));
|
|
263
|
+
|
|
264
|
+
const issueWithLocation = result.issues.find((i) => i.path && i.lineNumber);
|
|
265
|
+
expect(issueWithLocation).toBeDefined();
|
|
266
|
+
expect(issueWithLocation?.path).toContain('missing-intent.aps.md');
|
|
267
|
+
expect(typeof issueWithLocation?.lineNumber).toBe('number');
|
|
268
|
+
});
|
|
269
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# APS Index — [Project Name]
|
|
2
|
+
|
|
3
|
+
## Problem & Success Criteria
|
|
4
|
+
|
|
5
|
+
**Problem:** [What problem are we solving? Why does this work matter?]
|
|
6
|
+
|
|
7
|
+
**Success Criteria:**
|
|
8
|
+
|
|
9
|
+
- [ ] [Measurable outcome 1]
|
|
10
|
+
- [ ] [Measurable outcome 2]
|
|
11
|
+
- [ ] [How we know we're done]
|
|
12
|
+
|
|
13
|
+
## Scope
|
|
14
|
+
|
|
15
|
+
**In Scope:**
|
|
16
|
+
|
|
17
|
+
- [What this plan covers]
|
|
18
|
+
- [Boundaries of work]
|
|
19
|
+
|
|
20
|
+
**Out of Scope:**
|
|
21
|
+
|
|
22
|
+
- [What this plan explicitly excludes]
|
|
23
|
+
- [Things deferred to future work]
|
|
24
|
+
|
|
25
|
+
## System Map
|
|
26
|
+
|
|
27
|
+
[High-level view of modules and their relationships]
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
[Module A] ──→ [Module B] ──→ [Module C]
|
|
31
|
+
↑ ↓
|
|
32
|
+
[External Service] [Database]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Milestones
|
|
36
|
+
|
|
37
|
+
### M1: [Milestone Name]
|
|
38
|
+
|
|
39
|
+
- [What's included]
|
|
40
|
+
- Modules: [module-a, module-b]
|
|
41
|
+
- Target: [date]
|
|
42
|
+
|
|
43
|
+
### M2: [Milestone Name]
|
|
44
|
+
|
|
45
|
+
- [What's included]
|
|
46
|
+
- Modules: [module-c]
|
|
47
|
+
- Target: [date]
|
|
48
|
+
|
|
49
|
+
## Modules
|
|
50
|
+
|
|
51
|
+
### [module-id]
|
|
52
|
+
|
|
53
|
+
- **Path:** [./modules/[module-name].aps.md](./modules/[module-name].aps.md)
|
|
54
|
+
- **Scope:** [SCOPE]
|
|
55
|
+
- **Owner:** @[username]
|
|
56
|
+
- **Status:** Draft
|
|
57
|
+
- **Priority:** [low|medium|high]
|
|
58
|
+
- **Tags:** [tag1, tag2]
|
|
59
|
+
- **Dependencies:** [other-module-id]
|
|
60
|
+
|
|
61
|
+
### [another-module-id]
|
|
62
|
+
|
|
63
|
+
- **Path:**
|
|
64
|
+
[./modules/[another-module].aps.md](./modules/[another-module].aps.md)
|
|
65
|
+
- **Scope:** [SCOPE2]
|
|
66
|
+
- **Owner:** @[username]
|
|
67
|
+
- **Status:** Draft
|
|
68
|
+
- **Priority:** [low|medium|high]
|
|
69
|
+
- **Tags:** [tag1, tag2]
|
|
70
|
+
- **Dependencies:** (none)
|
|
71
|
+
|
|
72
|
+
## Epics
|
|
73
|
+
|
|
74
|
+
### [epic-id]
|
|
75
|
+
|
|
76
|
+
- **Path:** [./epics/[epic-name].aps.md](./epics/[epic-name].aps.md)
|
|
77
|
+
- **Owner:** @[username]
|
|
78
|
+
- **Modules:** [module-id-1, module-id-2]
|
|
79
|
+
- **Milestone:** M1
|
|
80
|
+
|
|
81
|
+
## Decisions
|
|
82
|
+
|
|
83
|
+
- **D-001:** [Short decision] — [rationale] ([ADR-001](./decisions/ADR-001.md))
|
|
84
|
+
- **D-002:** [Another decision] — [rationale]
|
|
85
|
+
|
|
86
|
+
## Risks
|
|
87
|
+
|
|
88
|
+
- **R-001:** [Risk description] — Mitigation: [approach]
|
|
89
|
+
- **R-002:** [Risk description] — Mitigation: [approach]
|
|
90
|
+
|
|
91
|
+
## Open Questions
|
|
92
|
+
|
|
93
|
+
- [Unresolved question 1]
|
|
94
|
+
- [Unresolved question 2]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# [Plan Title]
|
|
2
|
+
|
|
3
|
+
## Modules
|
|
4
|
+
|
|
5
|
+
### [module-id]
|
|
6
|
+
|
|
7
|
+
- **Path:** [./modules/[module-name].aps.md](./modules/[module-name].aps.md)
|
|
8
|
+
- **Scope:** [SCOPE]
|
|
9
|
+
- **Owner:** @[username]
|
|
10
|
+
|
|
11
|
+
### [another-module-id]
|
|
12
|
+
|
|
13
|
+
- **Path:**
|
|
14
|
+
[./modules/[another-module].aps.md](./modules/[another-module].aps.md)
|
|
15
|
+
- **Scope:** [SCOPE2]
|
|
16
|
+
- **Owner:** @[username]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# [Plan Title]
|
|
2
|
+
|
|
3
|
+
## Problem & Success Criteria
|
|
4
|
+
|
|
5
|
+
**Problem:** [What problem are we solving? Why does this work matter?]
|
|
6
|
+
|
|
7
|
+
**Success Criteria:**
|
|
8
|
+
|
|
9
|
+
- [ ] [Measurable outcome 1]
|
|
10
|
+
- [ ] [Measurable outcome 2]
|
|
11
|
+
- [ ] [How we know we're done]
|
|
12
|
+
|
|
13
|
+
## System Map
|
|
14
|
+
|
|
15
|
+
[High-level view of modules and their relationships]
|
|
16
|
+
|
|
17
|
+
- **[module-a]** → depends on → **[module-b]**
|
|
18
|
+
- **[module-c]** — standalone
|
|
19
|
+
|
|
20
|
+
## Milestones
|
|
21
|
+
|
|
22
|
+
### M1: [Milestone Name]
|
|
23
|
+
|
|
24
|
+
- [What's included]
|
|
25
|
+
- Target: [date or modules/features]
|
|
26
|
+
|
|
27
|
+
### M2: [Milestone Name]
|
|
28
|
+
|
|
29
|
+
- [What's included]
|
|
30
|
+
- Target: [date or modules/features]
|
|
31
|
+
|
|
32
|
+
## Modules
|
|
33
|
+
|
|
34
|
+
### [module-id]
|
|
35
|
+
|
|
36
|
+
- **Path:** [./modules/[module-name].aps.md](./modules/[module-name].aps.md)
|
|
37
|
+
- **Scope:** [SCOPE]
|
|
38
|
+
- **Owner:** @[username]
|
|
39
|
+
- **Status:** Draft
|
|
40
|
+
- **Priority:** [low|medium|high]
|
|
41
|
+
- **Tags:** [tag1, tag2]
|
|
42
|
+
- **Dependencies:** [other-module-id]
|
|
43
|
+
|
|
44
|
+
### [another-module-id]
|
|
45
|
+
|
|
46
|
+
- **Path:**
|
|
47
|
+
[./modules/[another-module].aps.md](./modules/[another-module].aps.md)
|
|
48
|
+
- **Scope:** [SCOPE2]
|
|
49
|
+
- **Owner:** @[username]
|
|
50
|
+
- **Status:** Draft
|
|
51
|
+
- **Priority:** [low|medium|high]
|
|
52
|
+
- **Tags:** [tag1, tag2]
|
|
53
|
+
- **Dependencies:** (none)
|
|
54
|
+
|
|
55
|
+
## Decisions
|
|
56
|
+
|
|
57
|
+
- **D-001:** [Short decision] — [rationale] ([ADR-001](./decisions/ADR-001.md))
|
|
58
|
+
- **D-002:** [Another decision] — [rationale]
|
|
59
|
+
|
|
60
|
+
## Open Questions
|
|
61
|
+
|
|
62
|
+
- [Unresolved question 1]
|
|
63
|
+
- [Unresolved question 2]
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Module APS — [Module Name]
|
|
2
|
+
|
|
3
|
+
**Scope:** [SCOPE] **Owner:** @[username] **Priority:** [low|medium|high]
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
[Why this module exists and what problem it solves. The "why" behind this work.]
|
|
8
|
+
|
|
9
|
+
## In Scope / Out of Scope
|
|
10
|
+
|
|
11
|
+
**In Scope:**
|
|
12
|
+
|
|
13
|
+
- [What this module WILL do]
|
|
14
|
+
- [Boundaries of responsibility]
|
|
15
|
+
- [Features included]
|
|
16
|
+
|
|
17
|
+
**Out of Scope:**
|
|
18
|
+
|
|
19
|
+
- [What this module will NOT do]
|
|
20
|
+
- [Things that belong elsewhere]
|
|
21
|
+
- [Explicit exclusions]
|
|
22
|
+
|
|
23
|
+
## Assumptions
|
|
24
|
+
|
|
25
|
+
- [Assumption 1] — Confidence: [low|medium|high]
|
|
26
|
+
- [Assumption 2] — Confidence: [low|medium|high]
|
|
27
|
+
|
|
28
|
+
## Interfaces
|
|
29
|
+
|
|
30
|
+
**Depends on:**
|
|
31
|
+
|
|
32
|
+
- [Service/Module name] — [what we need from it]
|
|
33
|
+
- [External API] — [what we consume]
|
|
34
|
+
|
|
35
|
+
**Exposes:**
|
|
36
|
+
|
|
37
|
+
- [Endpoint/API] — [what others can use]
|
|
38
|
+
- [Event/Hook] — [what we publish]
|
|
39
|
+
|
|
40
|
+
## Tasks
|
|
41
|
+
|
|
42
|
+
### [SCOPE]-001: [Task title]
|
|
43
|
+
|
|
44
|
+
**Intent:** [Clear statement of what this task aims to achieve] **Expected
|
|
45
|
+
Outcome:** [What success looks like] **Confidence:** [low|medium|high] **Link:**
|
|
46
|
+
[PROJ-123](https://jira.example.com/browse/PROJ-123) **Scopes:** [SCOPE1,
|
|
47
|
+
SCOPE2] **Tags:** [tag1, tag2, tag3] **Dependencies:** [SCOPE-XXX, OTHER-YYY]
|
|
48
|
+
**Inputs:**
|
|
49
|
+
|
|
50
|
+
- [Required input 1]
|
|
51
|
+
- [Required input 2]
|
|
52
|
+
|
|
53
|
+
### [SCOPE]-002: [Another task]
|
|
54
|
+
|
|
55
|
+
**Intent:** [What this task does] **Expected Outcome:** [Success criteria]
|
|
56
|
+
**Confidence:** [low|medium|high] **Link:**
|
|
57
|
+
[PROJ-124](https://jira.example.com/browse/PROJ-124) **Scopes:** [SCOPE]
|
|
58
|
+
**Dependencies:** [SCOPE]-001
|
|
59
|
+
|
|
60
|
+
## Decisions
|
|
61
|
+
|
|
62
|
+
- **D-001:** [Short decision] — [rationale] ([ADR-001](../decisions/ADR-001.md))
|
|
63
|
+
- **D-002:** [Another decision] — [rationale]
|
|
64
|
+
|
|
65
|
+
## Risks
|
|
66
|
+
|
|
67
|
+
- **R-001:** [Risk description] — Mitigation: [approach]
|
|
68
|
+
|
|
69
|
+
## Open Questions
|
|
70
|
+
|
|
71
|
+
- [Unresolved question about this module]
|
|
72
|
+
|
|
73
|
+
## Notes
|
|
74
|
+
|
|
75
|
+
- [Additional context or considerations]
|
|
76
|
+
- [Links to relevant resources]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# [Module Title]
|
|
2
|
+
|
|
3
|
+
**Scope:** [SCOPE] **Owner:** @[username]
|
|
4
|
+
|
|
5
|
+
## Tasks
|
|
6
|
+
|
|
7
|
+
### [SCOPE]-001: [Task title]
|
|
8
|
+
|
|
9
|
+
**Intent:** [What this task aims to achieve] **Confidence:** [low|medium|high]
|
|
10
|
+
|
|
11
|
+
### [SCOPE]-002: [Another task]
|
|
12
|
+
|
|
13
|
+
**Intent:** [What this task does] **Confidence:** [low|medium|high]
|
|
14
|
+
**Dependencies:** [SCOPE]-001
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# [Module Title]
|
|
2
|
+
|
|
3
|
+
**Scope:** [SCOPE] **Owner:** @[username] **Priority:** [low|medium|high]
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
[Why this module exists and what problem it solves]
|
|
8
|
+
|
|
9
|
+
## In Scope / Out of Scope
|
|
10
|
+
|
|
11
|
+
**In Scope:**
|
|
12
|
+
|
|
13
|
+
- [What this module WILL do]
|
|
14
|
+
- [Boundaries of responsibility]
|
|
15
|
+
|
|
16
|
+
**Out of Scope:**
|
|
17
|
+
|
|
18
|
+
- [What this module will NOT do]
|
|
19
|
+
- [Things that belong elsewhere]
|
|
20
|
+
|
|
21
|
+
## Interfaces
|
|
22
|
+
|
|
23
|
+
**Depends on:**
|
|
24
|
+
|
|
25
|
+
- [Service/Module name] — [what we need from it]
|
|
26
|
+
|
|
27
|
+
**Exposes:**
|
|
28
|
+
|
|
29
|
+
- [Endpoint/API] — [what others can use]
|
|
30
|
+
|
|
31
|
+
## Tasks
|
|
32
|
+
|
|
33
|
+
### [SCOPE]-001: [Task title]
|
|
34
|
+
|
|
35
|
+
**Intent:** [Clear statement of what this task aims to achieve] **Expected
|
|
36
|
+
Outcome:** [What success looks like] **Confidence:** [low|medium|high] **Link:**
|
|
37
|
+
[PROJ-123](https://jira.example.com/browse/PROJ-123) **Scopes:** [SCOPE1,
|
|
38
|
+
SCOPE2] **Tags:** [tag1, tag2, tag3] **Dependencies:** [SCOPE-XXX, OTHER-YYY]
|
|
39
|
+
**Inputs:**
|
|
40
|
+
|
|
41
|
+
- [Required input 1]
|
|
42
|
+
- [Required input 2]
|
|
43
|
+
|
|
44
|
+
### [SCOPE]-002: [Another task]
|
|
45
|
+
|
|
46
|
+
**Intent:** [What this task does] **Confidence:** [low|medium|high] **Scopes:**
|
|
47
|
+
[SCOPE] **Dependencies:** [SCOPE]-001
|
|
48
|
+
|
|
49
|
+
## Decisions
|
|
50
|
+
|
|
51
|
+
- **D-001:** [Short decision] — [rationale]
|
|
52
|
+
|
|
53
|
+
## Notes
|
|
54
|
+
|
|
55
|
+
- [Additional context or considerations]
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Feature: [Feature Name]
|
|
2
|
+
|
|
3
|
+
**Scope:** [SCOPE] **Owner:** @[username] **Priority:** [low|medium|high]
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
[Why we're building this feature and what problem it solves]
|
|
8
|
+
|
|
9
|
+
## Success Criteria
|
|
10
|
+
|
|
11
|
+
- [ ] [Measurable outcome 1]
|
|
12
|
+
- [ ] [Measurable outcome 2]
|
|
13
|
+
- [ ] [How we know we're done]
|
|
14
|
+
|
|
15
|
+
## In Scope / Out of Scope
|
|
16
|
+
|
|
17
|
+
**In Scope:**
|
|
18
|
+
|
|
19
|
+
- [What this feature WILL do]
|
|
20
|
+
|
|
21
|
+
**Out of Scope:**
|
|
22
|
+
|
|
23
|
+
- [What this feature will NOT do]
|
|
24
|
+
|
|
25
|
+
## Assumptions
|
|
26
|
+
|
|
27
|
+
- [Assumption 1] — Confidence: [low|medium|high]
|
|
28
|
+
|
|
29
|
+
## Tasks
|
|
30
|
+
|
|
31
|
+
### [SCOPE]-001: [First task]
|
|
32
|
+
|
|
33
|
+
**Intent:** [What this task achieves] **Expected Outcome:** [Success criteria]
|
|
34
|
+
**Confidence:** [low|medium|high] **Link:**
|
|
35
|
+
[PROJ-123](https://jira.example.com/browse/PROJ-123) **Scopes:** [SCOPE]
|
|
36
|
+
**Tags:** [tag1, tag2] **Inputs:**
|
|
37
|
+
|
|
38
|
+
- [Required input 1]
|
|
39
|
+
|
|
40
|
+
### [SCOPE]-002: [Second task]
|
|
41
|
+
|
|
42
|
+
**Intent:** [What this task achieves] **Expected Outcome:** [Success criteria]
|
|
43
|
+
**Confidence:** [low|medium|high] **Scopes:** [SCOPE] **Dependencies:**
|
|
44
|
+
[SCOPE]-001
|
|
45
|
+
|
|
46
|
+
## Decisions
|
|
47
|
+
|
|
48
|
+
- **D-001:** [Decision] — [rationale]
|
|
49
|
+
|
|
50
|
+
## Open Questions
|
|
51
|
+
|
|
52
|
+
- [Unresolved question]
|
|
53
|
+
|
|
54
|
+
## Notes
|
|
55
|
+
|
|
56
|
+
- [Additional notes or considerations]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# [Feature Name]
|
|
2
|
+
|
|
3
|
+
**Scope:** [SCOPE] **Owner:** @[username]
|
|
4
|
+
|
|
5
|
+
## Tasks
|
|
6
|
+
|
|
7
|
+
### [SCOPE]-001: [First task]
|
|
8
|
+
|
|
9
|
+
**Intent:** [What this task achieves] **Confidence:** [low|medium|high]
|
|
10
|
+
|
|
11
|
+
### [SCOPE]-002: [Second task]
|
|
12
|
+
|
|
13
|
+
**Intent:** [What this task achieves] **Confidence:** [low|medium|high]
|
|
14
|
+
**Dependencies:** [SCOPE]-001
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Feature: [Feature Name]
|
|
2
|
+
|
|
3
|
+
**Scope:** [SCOPE] **Owner:** @[username] **Priority:** [low|medium|high]
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
[Why we're building this feature and what problem it solves]
|
|
8
|
+
|
|
9
|
+
## Success Criteria
|
|
10
|
+
|
|
11
|
+
- [ ] [Measurable outcome 1]
|
|
12
|
+
- [ ] [Measurable outcome 2]
|
|
13
|
+
|
|
14
|
+
## Tasks
|
|
15
|
+
|
|
16
|
+
### [SCOPE]-001: [First task]
|
|
17
|
+
|
|
18
|
+
**Intent:** [What this task achieves] **Expected Outcome:** [Success criteria]
|
|
19
|
+
**Confidence:** [low|medium|high] **Link:**
|
|
20
|
+
[PROJ-123](https://jira.example.com/browse/PROJ-123) **Scopes:** [SCOPE]
|
|
21
|
+
**Tags:** [tag1, tag2]
|
|
22
|
+
|
|
23
|
+
### [SCOPE]-002: [Second task]
|
|
24
|
+
|
|
25
|
+
**Intent:** [What this task achieves] **Confidence:** [low|medium|high]
|
|
26
|
+
**Scopes:** [SCOPE] **Dependencies:** [SCOPE]-001
|
|
27
|
+
|
|
28
|
+
## Notes
|
|
29
|
+
|
|
30
|
+
- [Additional notes or considerations]
|