bmad-method-test-architecture-enterprise 1.17.0 → 1.17.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.
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"name": "bmad-method-test-architecture-enterprise",
|
|
13
13
|
"source": "./",
|
|
14
14
|
"description": "Master Test Architect module for quality strategy, test automation, CI/CD quality gates, and structured testing education. Part of the BMad Method ecosystem.",
|
|
15
|
-
"version": "1.17.
|
|
15
|
+
"version": "1.17.1",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "Murat K Ozcan (TEA Creator) & Brian (BMad) Madison"
|
|
18
18
|
},
|
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
14
14
|
- `actions/setup-node@v6`
|
|
15
15
|
- `actions/create-github-app-token@v3`
|
|
16
16
|
- Publish releases now use `[Unreleased]` changelog notes before falling back to generated GitHub release notes when an exact version section is missing.
|
|
17
|
+
- Documented workflow-local knowledge resources as intentional self-contained skill packaging and added validation for workflow-local knowledge indexes.
|
|
17
18
|
|
|
18
19
|
---
|
|
19
20
|
|
package/README.md
CHANGED
|
@@ -43,9 +43,12 @@ TEA has two layers of files, and each has a specific job:
|
|
|
43
43
|
| `steps-v/*.md` | **Validate** steps — always 1 file: evaluate against checklist | On demand |
|
|
44
44
|
| `checklist.md` | Validation criteria — what "done" looks like for this workflow | Read by steps-v |
|
|
45
45
|
| `*-template.md` | Output skeleton with `{PLACEHOLDER}` vars — steps fill these in to produce the final artifact | Read by steps-c when generating output |
|
|
46
|
-
| `src/agents/bmad-tea/resources/tea-index.csv` |
|
|
46
|
+
| `src/agents/bmad-tea/resources/tea-index.csv` | Agent-level knowledge fragment index — id, name, tags, tier (core/extended/specialized), file path | Read by the TEA agent for direct recommendations |
|
|
47
|
+
| `src/workflows/testarch/<workflow>/resources/` | Workflow-local knowledge index and fragments | Read by workflow steps from that workflow's skill root |
|
|
47
48
|
| `resources/knowledge/*.md` | Reusable fragments — standards, patterns, API references | Selectively read into context based on tier + config |
|
|
48
49
|
|
|
50
|
+
Workflow resource directories intentionally duplicate the TEA knowledge base. Each workflow skill must stay self-contained so it can be installed, copied, or invoked without reaching across skill boundaries. When knowledge changes, propagate the intended updates to the affected workflow resource directories instead of replacing them with a central runtime path.
|
|
51
|
+
|
|
49
52
|
```mermaid
|
|
50
53
|
flowchart LR
|
|
51
54
|
U[User] --> A[Agent Persona]
|
|
@@ -96,6 +96,8 @@ network-first,Network-First Safeguards,Intercept-before-navigate workflow,"netwo
|
|
|
96
96
|
fixture-architecture,Fixture Architecture,Composable fixture patterns,"fixtures,architecture",knowledge/fixture-architecture.md
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
+
The agent-level `resources/` directory is the reference catalog for Murat. Workflow skills also carry their own `resources/tea-index.csv` and `resources/knowledge/` directories. That duplication is intentional: workflow step frontmatter resolves `knowledgeIndex: './resources/tea-index.csv'` from `{skill-root}`, keeping each workflow skill modular and self-contained.
|
|
100
|
+
|
|
99
101
|
**2. Workflow Loads Relevant Fragments**
|
|
100
102
|
|
|
101
103
|
When user runs `atdd`:
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "bmad-method-test-architecture-enterprise",
|
|
4
|
-
"version": "1.17.
|
|
4
|
+
"version": "1.17.1",
|
|
5
5
|
"description": "Master Test Architect for quality strategy, test automation, and release gates",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"bmad",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
const path = require('node:path');
|
|
14
14
|
const fs = require('node:fs/promises');
|
|
15
|
+
const { parse } = require('csv-parse/sync');
|
|
15
16
|
const yaml = require('js-yaml');
|
|
16
17
|
|
|
17
18
|
async function pathExists(filePath) {
|
|
@@ -23,6 +24,11 @@ async function pathExists(filePath) {
|
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
function extractFrontmatter(content) {
|
|
28
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
|
29
|
+
return match ? match[1] : '';
|
|
30
|
+
}
|
|
31
|
+
|
|
26
32
|
// ANSI colors
|
|
27
33
|
const colors = {
|
|
28
34
|
reset: '\u001B[0m',
|
|
@@ -253,10 +259,12 @@ async function runTests() {
|
|
|
253
259
|
];
|
|
254
260
|
|
|
255
261
|
for (const dirName of workflowDirs) {
|
|
262
|
+
const workflowDir = path.join(projectRoot, `src/workflows/testarch/${dirName}`);
|
|
256
263
|
const skillMdPath = path.join(projectRoot, `src/workflows/testarch/${dirName}/SKILL.md`);
|
|
257
264
|
const customizeTomlPath = path.join(projectRoot, `src/workflows/testarch/${dirName}/customize.toml`);
|
|
258
265
|
const workflowYamlPath = path.join(projectRoot, `src/workflows/testarch/${dirName}/workflow.yaml`);
|
|
259
266
|
const instructionsMdPath = path.join(projectRoot, `src/workflows/testarch/${dirName}/instructions.md`);
|
|
267
|
+
let workflowKnowledgeIndexValidated = false;
|
|
260
268
|
|
|
261
269
|
if (await pathExists(skillMdPath)) {
|
|
262
270
|
try {
|
|
@@ -344,6 +352,7 @@ async function runTests() {
|
|
|
344
352
|
const stepPath = path.join(stepDirPath, fileName);
|
|
345
353
|
try {
|
|
346
354
|
const stepContent = await fs.readFile(stepPath, 'utf8');
|
|
355
|
+
const frontmatter = extractFrontmatter(stepContent);
|
|
347
356
|
const stepLabel = `${dirName}/${stepDir}/${fileName}`;
|
|
348
357
|
|
|
349
358
|
assert(!stepContent.includes("nextStepFile: './"), `${stepLabel} has no cwd-sensitive nextStepFile`);
|
|
@@ -371,6 +380,46 @@ async function runTests() {
|
|
|
371
380
|
if (stepContent.includes('workflowPath:')) {
|
|
372
381
|
assert(stepContent.includes("workflowPath: '{skill-root}'"), `${stepLabel} anchors workflowPath to {skill-root}`);
|
|
373
382
|
}
|
|
383
|
+
|
|
384
|
+
if (frontmatter.includes('knowledgeIndex:')) {
|
|
385
|
+
const knowledgeIndexMatch = frontmatter.match(/^knowledgeIndex:\s*['"]([^'"]+)['"]/m);
|
|
386
|
+
assert(Boolean(knowledgeIndexMatch), `${stepLabel} declares a parseable knowledgeIndex`);
|
|
387
|
+
|
|
388
|
+
const knowledgeIndexReference = knowledgeIndexMatch ? knowledgeIndexMatch[1] : '';
|
|
389
|
+
const knowledgeIndexPath = path.resolve(workflowDir, knowledgeIndexReference);
|
|
390
|
+
const expectedKnowledgeIndexPath = path.join(workflowDir, 'resources', 'tea-index.csv');
|
|
391
|
+
|
|
392
|
+
assert(knowledgeIndexPath === expectedKnowledgeIndexPath, `${stepLabel} uses the workflow-local knowledge index`);
|
|
393
|
+
assert(await pathExists(knowledgeIndexPath), `${stepLabel} knowledgeIndex target exists`);
|
|
394
|
+
|
|
395
|
+
if (!workflowKnowledgeIndexValidated && (await pathExists(knowledgeIndexPath))) {
|
|
396
|
+
const records = parse(await fs.readFile(knowledgeIndexPath, 'utf8'), { columns: true, skip_empty_lines: true });
|
|
397
|
+
const workflowKnowledgeDir = path.join(path.dirname(knowledgeIndexPath), 'knowledge');
|
|
398
|
+
const workflowKnowledgeFiles = (await fs.readdir(workflowKnowledgeDir)).filter((name) => name.endsWith('.md'));
|
|
399
|
+
const missingFragments = [];
|
|
400
|
+
|
|
401
|
+
for (const record of records) {
|
|
402
|
+
if (!record.fragment_file) {
|
|
403
|
+
missingFragments.push(`${record.id || '<missing-id>'}: missing fragment_file`);
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const fragmentPath = path.resolve(path.dirname(knowledgeIndexPath), record.fragment_file);
|
|
408
|
+
if (!(await pathExists(fragmentPath))) {
|
|
409
|
+
missingFragments.push(record.fragment_file);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
assert(
|
|
414
|
+
records.length === workflowKnowledgeFiles.length,
|
|
415
|
+
`${dirName}/resources/tea-index.csv line count matches workflow-local fragments`,
|
|
416
|
+
`Found ${records.length} records for ${workflowKnowledgeFiles.length} fragments`,
|
|
417
|
+
);
|
|
418
|
+
assert(missingFragments.length === 0, `${dirName}/resources/tea-index.csv fragment files exist`, missingFragments.join(', '));
|
|
419
|
+
|
|
420
|
+
workflowKnowledgeIndexValidated = true;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
374
423
|
} catch (error) {
|
|
375
424
|
assert(false, `${dirName}/${stepDir}/${fileName} validates`, error.message);
|
|
376
425
|
}
|