rhachet-roles-bhuild 0.1.3 → 0.4.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/dist/domain.operations/behavior/bind/flattenBranchName.cli.d.ts +2 -0
- package/dist/domain.operations/behavior/bind/flattenBranchName.cli.js +19 -0
- package/dist/domain.operations/behavior/bind/flattenBranchName.cli.js.map +1 -0
- package/dist/domain.operations/behavior/bind/flattenBranchName.d.ts +8 -0
- package/dist/domain.operations/behavior/bind/flattenBranchName.js +19 -0
- package/dist/domain.operations/behavior/bind/flattenBranchName.js.map +1 -0
- package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.cli.d.ts +2 -0
- package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.cli.js +18 -0
- package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.cli.js.map +1 -0
- package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.d.ts +11 -0
- package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.js +51 -0
- package/dist/domain.operations/behavior/bind/getBoundBehaviorByBranch.js.map +1 -0
- package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.cli.d.ts +2 -0
- package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.cli.js +20 -0
- package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.cli.js.map +1 -0
- package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.d.ts +11 -0
- package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.js +51 -0
- package/dist/domain.operations/behavior/bind/getLatestBlueprintByBehavior.js.map +1 -0
- package/dist/domain.operations/behavior/bind/index.d.ts +3 -0
- package/dist/domain.operations/behavior/bind/index.js +10 -0
- package/dist/domain.operations/behavior/bind/index.js.map +1 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.blueprint/rule.require.criteria-satisfied.md +37 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.blueprint/rule.require.determinism-declared.md +44 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.blueprint/rule.require.test-coverage-specified.md +42 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.blueprint/rule.require.test-patterns-specified.md +43 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.criteria/rule.prefer.dependency-order.md +43 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.criteria/rule.prefer.depth-groups.md +44 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.criteria/rule.prefer.usecase-groups.md +41 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.criteria/rule.require.bdd-format.md +25 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.roadmap/rule.prefer.clear-deliverables.md +46 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.roadmap/rule.prefer.dependency-order.md +59 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.wish/rule.prefer.bounded-scope.md +29 -0
- package/dist/domain.roles/behaver/briefs/practices/behavior.wish/rule.prefer.clear-desires.md +31 -0
- package/dist/domain.roles/behaver/getBehaverRole.js +4 -0
- package/dist/domain.roles/behaver/getBehaverRole.js.map +1 -1
- package/dist/domain.roles/behaver/inits/claude.hooks/sessionstart.boot-behavior.sh +109 -0
- package/dist/domain.roles/behaver/inits/init.claude.hooks.findsert.sh +226 -0
- package/dist/domain.roles/behaver/inits/init.claude.hooks.sh +34 -0
- package/dist/domain.roles/behaver/skills/bind.behavior.sh +236 -0
- package/dist/domain.roles/behaver/skills/init.behavior.sh +51 -0
- package/dist/domain.roles/behaver/skills/review.behavior.sh +396 -0
- package/dist/domain.roles/behaver/skills/review.behavior.test.utils.d.ts +12 -0
- package/dist/domain.roles/behaver/skills/review.behavior.test.utils.js +63 -0
- package/dist/domain.roles/behaver/skills/review.behavior.test.utils.js.map +1 -0
- package/dist/domain.roles/behaver/skills/review.deliverable.sh +344 -0
- package/package.json +10 -8
- package/readme.md +34 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const flattenBranchName_1 = require("./flattenBranchName");
|
|
5
|
+
/**
|
|
6
|
+
* .what = CLI entry point for flattenBranchName
|
|
7
|
+
* .why = enables shell scripts to call this operation via npx tsx
|
|
8
|
+
*/
|
|
9
|
+
const main = () => {
|
|
10
|
+
const branchName = process.argv[2];
|
|
11
|
+
if (!branchName) {
|
|
12
|
+
console.error('usage: flattenBranchName.cli.ts <branchName>');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
const flattened = (0, flattenBranchName_1.flattenBranchName)({ branchName });
|
|
16
|
+
console.log(flattened);
|
|
17
|
+
};
|
|
18
|
+
main();
|
|
19
|
+
//# sourceMappingURL=flattenBranchName.cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flattenBranchName.cli.js","sourceRoot":"","sources":["../../../../src/domain.operations/behavior/bind/flattenBranchName.cli.ts"],"names":[],"mappings":";;;AAEA,2DAAwD;AAExD;;;GAGG;AACH,MAAM,IAAI,GAAG,GAAS,EAAE;IACtB,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,SAAS,GAAG,IAAA,qCAAiB,EAAC,EAAE,UAAU,EAAE,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AACzB,CAAC,CAAC;AAEF,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* .what = flatten branch name to filesystem-safe format
|
|
3
|
+
* .why = bind flag filenames cannot contain forward slashes;
|
|
4
|
+
* this utility normalizes branch names for use in flag paths
|
|
5
|
+
*/
|
|
6
|
+
export declare const flattenBranchName: (input: {
|
|
7
|
+
branchName: string;
|
|
8
|
+
}) => string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.flattenBranchName = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* .what = flatten branch name to filesystem-safe format
|
|
6
|
+
* .why = bind flag filenames cannot contain forward slashes;
|
|
7
|
+
* this utility normalizes branch names for use in flag paths
|
|
8
|
+
*/
|
|
9
|
+
const flattenBranchName = (input) => {
|
|
10
|
+
// replace forward slashes with dots
|
|
11
|
+
let flattened = input.branchName.replace(/\//g, '.');
|
|
12
|
+
// normalize other special characters (keep alphanumeric, dots, dashes, underscores)
|
|
13
|
+
flattened = flattened.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
14
|
+
// remove trailing underscore if present
|
|
15
|
+
flattened = flattened.replace(/_$/, '');
|
|
16
|
+
return flattened;
|
|
17
|
+
};
|
|
18
|
+
exports.flattenBranchName = flattenBranchName;
|
|
19
|
+
//# sourceMappingURL=flattenBranchName.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flattenBranchName.js","sourceRoot":"","sources":["../../../../src/domain.operations/behavior/bind/flattenBranchName.ts"],"names":[],"mappings":";;;AAAA;;;;GAIG;AACI,MAAM,iBAAiB,GAAG,CAAC,KAA6B,EAAU,EAAE;IACzE,oCAAoC;IACpC,IAAI,SAAS,GAAG,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAErD,oFAAoF;IACpF,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;IAEvD,wCAAwC;IACxC,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAExC,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAXW,QAAA,iBAAiB,qBAW5B"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const getBoundBehaviorByBranch_1 = require("./getBoundBehaviorByBranch");
|
|
5
|
+
/**
|
|
6
|
+
* .what = CLI entry point for getBoundBehaviorByBranch
|
|
7
|
+
* .why = enables shell scripts to call this operation via npx tsx
|
|
8
|
+
*/
|
|
9
|
+
const main = () => {
|
|
10
|
+
const branchName = process.argv[2]; // optional
|
|
11
|
+
const result = (0, getBoundBehaviorByBranch_1.getBoundBehaviorByBranch)({
|
|
12
|
+
branchName: branchName || undefined,
|
|
13
|
+
});
|
|
14
|
+
// output as JSON for shell parsing
|
|
15
|
+
console.log(JSON.stringify(result));
|
|
16
|
+
};
|
|
17
|
+
main();
|
|
18
|
+
//# sourceMappingURL=getBoundBehaviorByBranch.cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getBoundBehaviorByBranch.cli.js","sourceRoot":"","sources":["../../../../src/domain.operations/behavior/bind/getBoundBehaviorByBranch.cli.ts"],"names":[],"mappings":";;;AAEA,yEAAsE;AAEtE;;;GAGG;AACH,MAAM,IAAI,GAAG,GAAS,EAAE;IACtB,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW;IAE/C,MAAM,MAAM,GAAG,IAAA,mDAAwB,EAAC;QACtC,UAAU,EAAE,UAAU,IAAI,SAAS;KACpC,CAAC,CAAC;IAEH,mCAAmC;IACnC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;AACtC,CAAC,CAAC;AAEF,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* .what = find which behavior (if any) a branch is bound to
|
|
3
|
+
* .why = both hooks and skills need to discover bindings
|
|
4
|
+
*/
|
|
5
|
+
export declare const getBoundBehaviorByBranch: (input: {
|
|
6
|
+
branchName?: string;
|
|
7
|
+
cwd?: string;
|
|
8
|
+
}) => {
|
|
9
|
+
behaviorDir: string | null;
|
|
10
|
+
bindings: string[];
|
|
11
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getBoundBehaviorByBranch = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const flattenBranchName_1 = require("./flattenBranchName");
|
|
8
|
+
/**
|
|
9
|
+
* .what = find which behavior (if any) a branch is bound to
|
|
10
|
+
* .why = both hooks and skills need to discover bindings
|
|
11
|
+
*/
|
|
12
|
+
const getBoundBehaviorByBranch = (input) => {
|
|
13
|
+
const cwd = input.cwd ?? process.cwd();
|
|
14
|
+
// get the current branch name if not provided
|
|
15
|
+
const branchName = input.branchName ??
|
|
16
|
+
(0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', {
|
|
17
|
+
cwd,
|
|
18
|
+
encoding: 'utf-8',
|
|
19
|
+
}).trim();
|
|
20
|
+
// flatten the branch name for filesystem lookup
|
|
21
|
+
const flatBranch = (0, flattenBranchName_1.flattenBranchName)({ branchName });
|
|
22
|
+
const flagFileName = `${flatBranch}.flag`;
|
|
23
|
+
// search for .behavior/*/.bind/${flagFileName}
|
|
24
|
+
const behaviorRoot = (0, path_1.join)(cwd, '.behavior');
|
|
25
|
+
if (!(0, fs_1.existsSync)(behaviorRoot))
|
|
26
|
+
return { behaviorDir: null, bindings: [] };
|
|
27
|
+
// find all behavior directories
|
|
28
|
+
const behaviorDirs = (0, fs_1.readdirSync)(behaviorRoot, { withFileTypes: true })
|
|
29
|
+
.filter((dirent) => dirent.isDirectory())
|
|
30
|
+
.map((dirent) => dirent.name);
|
|
31
|
+
// check each behavior for a bind flag
|
|
32
|
+
const bindings = [];
|
|
33
|
+
for (const behaviorDirName of behaviorDirs) {
|
|
34
|
+
const bindDir = (0, path_1.join)(behaviorRoot, behaviorDirName, '.bind');
|
|
35
|
+
const flagPath = (0, path_1.join)(bindDir, flagFileName);
|
|
36
|
+
if ((0, fs_1.existsSync)(flagPath)) {
|
|
37
|
+
bindings.push((0, path_1.join)(behaviorRoot, behaviorDirName));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// return based on how many bindings found
|
|
41
|
+
if (bindings.length === 0)
|
|
42
|
+
return { behaviorDir: null, bindings: [] };
|
|
43
|
+
// single binding found
|
|
44
|
+
const singleBinding = bindings[0];
|
|
45
|
+
if (bindings.length === 1 && singleBinding)
|
|
46
|
+
return { behaviorDir: singleBinding, bindings };
|
|
47
|
+
// multiple bindings found - return null for behaviorDir, let caller decide
|
|
48
|
+
return { behaviorDir: null, bindings };
|
|
49
|
+
};
|
|
50
|
+
exports.getBoundBehaviorByBranch = getBoundBehaviorByBranch;
|
|
51
|
+
//# sourceMappingURL=getBoundBehaviorByBranch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getBoundBehaviorByBranch.js","sourceRoot":"","sources":["../../../../src/domain.operations/behavior/bind/getBoundBehaviorByBranch.ts"],"names":[],"mappings":";;;AAAA,iDAAyC;AACzC,2BAA6C;AAC7C,+BAA4B;AAE5B,2DAAwD;AAExD;;;GAGG;AACI,MAAM,wBAAwB,GAAG,CAAC,KAGxC,EAAsD,EAAE;IACvD,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAEvC,8CAA8C;IAC9C,MAAM,UAAU,GACd,KAAK,CAAC,UAAU;QAChB,IAAA,wBAAQ,EAAC,iCAAiC,EAAE;YAC1C,GAAG;YACH,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC,IAAI,EAAE,CAAC;IAEZ,gDAAgD;IAChD,MAAM,UAAU,GAAG,IAAA,qCAAiB,EAAC,EAAE,UAAU,EAAE,CAAC,CAAC;IACrD,MAAM,YAAY,GAAG,GAAG,UAAU,OAAO,CAAC;IAE1C,+CAA+C;IAC/C,MAAM,YAAY,GAAG,IAAA,WAAI,EAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAA,eAAU,EAAC,YAAY,CAAC;QAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAE1E,gCAAgC;IAChC,MAAM,YAAY,GAAG,IAAA,gBAAW,EAAC,YAAY,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SACpE,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;SACxC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAEhC,sCAAsC;IACtC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,eAAe,IAAI,YAAY,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,IAAA,WAAI,EAAC,YAAY,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC;QAC7D,MAAM,QAAQ,GAAG,IAAA,WAAI,EAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QAC7C,IAAI,IAAA,eAAU,EAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,QAAQ,CAAC,IAAI,CAAC,IAAA,WAAI,EAAC,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,0CAA0C;IAC1C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAEtE,uBAAuB;IACvB,MAAM,aAAa,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAClC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,aAAa;QACxC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC;IAElD,2EAA2E;IAC3E,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AACzC,CAAC,CAAC;AA/CW,QAAA,wBAAwB,4BA+CnC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const getLatestBlueprintByBehavior_1 = require("./getLatestBlueprintByBehavior");
|
|
5
|
+
/**
|
|
6
|
+
* .what = CLI entry point for getLatestBlueprintByBehavior
|
|
7
|
+
* .why = enables shell scripts to call this operation via npx tsx
|
|
8
|
+
*/
|
|
9
|
+
const main = () => {
|
|
10
|
+
const behaviorDir = process.argv[2];
|
|
11
|
+
if (!behaviorDir) {
|
|
12
|
+
console.error('usage: getLatestBlueprintByBehavior.cli.ts <behaviorDir>');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
const result = (0, getLatestBlueprintByBehavior_1.getLatestBlueprintByBehavior)({ behaviorDir });
|
|
16
|
+
// output the path or empty string if none
|
|
17
|
+
console.log(result ?? '');
|
|
18
|
+
};
|
|
19
|
+
main();
|
|
20
|
+
//# sourceMappingURL=getLatestBlueprintByBehavior.cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getLatestBlueprintByBehavior.cli.js","sourceRoot":"","sources":["../../../../src/domain.operations/behavior/bind/getLatestBlueprintByBehavior.cli.ts"],"names":[],"mappings":";;;AAEA,iFAA8E;AAE9E;;;GAGG;AACH,MAAM,IAAI,GAAG,GAAS,EAAE;IACtB,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;QAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,IAAA,2DAA4B,EAAC,EAAE,WAAW,EAAE,CAAC,CAAC;IAE7D,0CAA0C;IAC1C,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;AAC5B,CAAC,CAAC;AAEF,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* .what = resolve the latest blueprint version from a behavior directory
|
|
3
|
+
* .why = both hooks and review.deliverable need this logic
|
|
4
|
+
*
|
|
5
|
+
* .note = version precedence:
|
|
6
|
+
* - v3.i2 > v2.i3 (major version wins)
|
|
7
|
+
* - v2.i3 > v2.i1 (latest iteration within major)
|
|
8
|
+
*/
|
|
9
|
+
export declare const getLatestBlueprintByBehavior: (input: {
|
|
10
|
+
behaviorDir: string;
|
|
11
|
+
}) => string | null;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getLatestBlueprintByBehavior = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
/**
|
|
7
|
+
* .what = resolve the latest blueprint version from a behavior directory
|
|
8
|
+
* .why = both hooks and review.deliverable need this logic
|
|
9
|
+
*
|
|
10
|
+
* .note = version precedence:
|
|
11
|
+
* - v3.i2 > v2.i3 (major version wins)
|
|
12
|
+
* - v2.i3 > v2.i1 (latest iteration within major)
|
|
13
|
+
*/
|
|
14
|
+
const getLatestBlueprintByBehavior = (input) => {
|
|
15
|
+
// find all blueprint files matching pattern: *.blueprint.v*.i*.md
|
|
16
|
+
const blueprintPattern = /\.blueprint\.v(\d+)\.i(\d+)\.md$/;
|
|
17
|
+
let files;
|
|
18
|
+
try {
|
|
19
|
+
files = (0, fs_1.readdirSync)(input.behaviorDir);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
// parse version info from each matching file
|
|
25
|
+
const blueprints = [];
|
|
26
|
+
for (const file of files) {
|
|
27
|
+
const match = file.match(blueprintPattern);
|
|
28
|
+
const majorVersionStr = match?.[1];
|
|
29
|
+
const iterationStr = match?.[2];
|
|
30
|
+
if (match && majorVersionStr && iterationStr) {
|
|
31
|
+
blueprints.push({
|
|
32
|
+
path: (0, path_1.join)(input.behaviorDir, file),
|
|
33
|
+
majorVersion: parseInt(majorVersionStr, 10),
|
|
34
|
+
iteration: parseInt(iterationStr, 10),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (blueprints.length === 0)
|
|
39
|
+
return null;
|
|
40
|
+
// sort by major version (descending), then by iteration (descending)
|
|
41
|
+
blueprints.sort((a, b) => {
|
|
42
|
+
if (a.majorVersion !== b.majorVersion)
|
|
43
|
+
return b.majorVersion - a.majorVersion;
|
|
44
|
+
return b.iteration - a.iteration;
|
|
45
|
+
});
|
|
46
|
+
// return the path to the latest blueprint
|
|
47
|
+
const latestBlueprint = blueprints[0];
|
|
48
|
+
return latestBlueprint?.path ?? null;
|
|
49
|
+
};
|
|
50
|
+
exports.getLatestBlueprintByBehavior = getLatestBlueprintByBehavior;
|
|
51
|
+
//# sourceMappingURL=getLatestBlueprintByBehavior.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getLatestBlueprintByBehavior.js","sourceRoot":"","sources":["../../../../src/domain.operations/behavior/bind/getLatestBlueprintByBehavior.ts"],"names":[],"mappings":";;;AAAA,2BAAiC;AACjC,+BAA4B;AAE5B;;;;;;;GAOG;AACI,MAAM,4BAA4B,GAAG,CAAC,KAE5C,EAAiB,EAAE;IAClB,kEAAkE;IAClE,MAAM,gBAAgB,GAAG,kCAAkC,CAAC;IAE5D,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,KAAK,GAAG,IAAA,gBAAW,EAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,6CAA6C;IAC7C,MAAM,UAAU,GAIX,EAAE,CAAC;IAER,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAC3C,MAAM,eAAe,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,YAAY,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,KAAK,IAAI,eAAe,IAAI,YAAY,EAAE,CAAC;YAC7C,UAAU,CAAC,IAAI,CAAC;gBACd,IAAI,EAAE,IAAA,WAAI,EAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC;gBACnC,YAAY,EAAE,QAAQ,CAAC,eAAe,EAAE,EAAE,CAAC;gBAC3C,SAAS,EAAE,QAAQ,CAAC,YAAY,EAAE,EAAE,CAAC;aACtC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEzC,qEAAqE;IACrE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACvB,IAAI,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,YAAY;YACnC,OAAO,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC;QACzC,OAAO,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,0CAA0C;IAC1C,MAAM,eAAe,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IACtC,OAAO,eAAe,EAAE,IAAI,IAAI,IAAI,CAAC;AACvC,CAAC,CAAC;AA7CW,QAAA,4BAA4B,gCA6CvC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getLatestBlueprintByBehavior = exports.getBoundBehaviorByBranch = exports.flattenBranchName = void 0;
|
|
4
|
+
var flattenBranchName_1 = require("./flattenBranchName");
|
|
5
|
+
Object.defineProperty(exports, "flattenBranchName", { enumerable: true, get: function () { return flattenBranchName_1.flattenBranchName; } });
|
|
6
|
+
var getBoundBehaviorByBranch_1 = require("./getBoundBehaviorByBranch");
|
|
7
|
+
Object.defineProperty(exports, "getBoundBehaviorByBranch", { enumerable: true, get: function () { return getBoundBehaviorByBranch_1.getBoundBehaviorByBranch; } });
|
|
8
|
+
var getLatestBlueprintByBehavior_1 = require("./getLatestBlueprintByBehavior");
|
|
9
|
+
Object.defineProperty(exports, "getLatestBlueprintByBehavior", { enumerable: true, get: function () { return getLatestBlueprintByBehavior_1.getLatestBlueprintByBehavior; } });
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/domain.operations/behavior/bind/index.ts"],"names":[],"mappings":";;;AAAA,yDAAwD;AAA/C,sHAAA,iBAAiB,OAAA;AAC1B,uEAAsE;AAA7D,oIAAA,wBAAwB,OAAA;AACjC,+EAA8E;AAArE,4IAAA,4BAA4B,OAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
.rule = require.criteria-satisfied
|
|
2
|
+
|
|
3
|
+
.what = blueprints must cover all declared criteria
|
|
4
|
+
|
|
5
|
+
.why = ensures no requirements are missed in implementation; criteria define the contract that the implementation must fulfill
|
|
6
|
+
|
|
7
|
+
.how = cross-reference blueprint sections against criteria usecases; verify each usecase has corresponding implementation detail
|
|
8
|
+
|
|
9
|
+
.examples:
|
|
10
|
+
.positive:
|
|
11
|
+
- |
|
|
12
|
+
## criteria coverage
|
|
13
|
+
|
|
14
|
+
| usecase | blueprint section |
|
|
15
|
+
|---------|-------------------|
|
|
16
|
+
| usecase.1 = rule briefs discoverable | deliverable.1 = rule briefs |
|
|
17
|
+
| usecase.2 = reviewing wish | deliverable.1, rule specifications |
|
|
18
|
+
| usecase.3 = reviewing criteria | deliverable.1, rule specifications |
|
|
19
|
+
| usecase.6 = composite skill | deliverable.2 = composite skill |
|
|
20
|
+
| usecase.7 = builds on bhrain | deliverable.2, implementation pattern |
|
|
21
|
+
.negative:
|
|
22
|
+
- |
|
|
23
|
+
## implementation
|
|
24
|
+
|
|
25
|
+
we will create a skill that reviews behaviors.
|
|
26
|
+
|
|
27
|
+
## deliverables
|
|
28
|
+
|
|
29
|
+
- review.behavior.sh
|
|
30
|
+
- |
|
|
31
|
+
## blueprint
|
|
32
|
+
|
|
33
|
+
this implements the wish by creating rule briefs and a skill.
|
|
34
|
+
|
|
35
|
+
(no explicit criteria mapping)
|
|
36
|
+
|
|
37
|
+
.severity = BLOCKER
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
.rule = require.determinism-declared
|
|
2
|
+
|
|
3
|
+
.what = blueprints must declare which parts are deterministic vs probabilistic
|
|
4
|
+
|
|
5
|
+
.why = different test strategies apply to each; deterministic code can be assertion-tested; probabilistic code requires example-based or snapshot testing
|
|
6
|
+
|
|
7
|
+
.how = check for explicit determinism classification of components; verify probabilistic components have example references
|
|
8
|
+
|
|
9
|
+
.examples:
|
|
10
|
+
.positive:
|
|
11
|
+
- |
|
|
12
|
+
## testing
|
|
13
|
+
|
|
14
|
+
### deterministic components
|
|
15
|
+
- argument parse
|
|
16
|
+
- behavior directory resolution
|
|
17
|
+
- artifact file resolution
|
|
18
|
+
- bhrain invocation command construction
|
|
19
|
+
- output file path generation
|
|
20
|
+
|
|
21
|
+
### probabilistic components
|
|
22
|
+
- bhrain review feedback content (llm-generated)
|
|
23
|
+
- reference: bhrain already has examples of review output
|
|
24
|
+
.negative:
|
|
25
|
+
- |
|
|
26
|
+
## testing
|
|
27
|
+
|
|
28
|
+
### test coverage
|
|
29
|
+
|
|
30
|
+
**unit tests**
|
|
31
|
+
- test all the things
|
|
32
|
+
|
|
33
|
+
**integration tests**
|
|
34
|
+
- test more things
|
|
35
|
+
- |
|
|
36
|
+
## implementation
|
|
37
|
+
|
|
38
|
+
the skill generates feedback using an llm.
|
|
39
|
+
|
|
40
|
+
## testing
|
|
41
|
+
|
|
42
|
+
we will test the output.
|
|
43
|
+
|
|
44
|
+
.severity = BLOCKER
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
.rule = require.test-coverage-specified
|
|
2
|
+
|
|
3
|
+
.what = blueprints must specify test coverage for all components
|
|
4
|
+
|
|
5
|
+
.why = untested code should never reach production; explicit test coverage specification ensures verification strategy is planned upfront
|
|
6
|
+
|
|
7
|
+
.how = verify unit/integration/acceptance test specifications exist; check that each component has declared test coverage level
|
|
8
|
+
|
|
9
|
+
.examples:
|
|
10
|
+
.positive:
|
|
11
|
+
- |
|
|
12
|
+
## testing
|
|
13
|
+
|
|
14
|
+
### test coverage
|
|
15
|
+
|
|
16
|
+
**unit tests** (review.behavior.test.ts)
|
|
17
|
+
- argument parse validates required args
|
|
18
|
+
- behavior directory resolution finds correct match
|
|
19
|
+
- artifact file resolution finds correct files
|
|
20
|
+
|
|
21
|
+
**integration tests** (review.behavior.integration.test.ts)
|
|
22
|
+
- given valid behavior, review produces feedback files
|
|
23
|
+
- given absent criteria, review warns but continues
|
|
24
|
+
|
|
25
|
+
**acceptance tests**
|
|
26
|
+
- npx rhachet run --repo bhuild --skill review.behavior --of valid-behavior
|
|
27
|
+
- produces feedback files collocated with artifacts
|
|
28
|
+
.negative:
|
|
29
|
+
- |
|
|
30
|
+
## implementation
|
|
31
|
+
|
|
32
|
+
the skill will parse arguments, resolve directories, and invoke bhrain.
|
|
33
|
+
|
|
34
|
+
## notes
|
|
35
|
+
|
|
36
|
+
should probably add tests later.
|
|
37
|
+
- |
|
|
38
|
+
## testing
|
|
39
|
+
|
|
40
|
+
tests will be written as needed.
|
|
41
|
+
|
|
42
|
+
.severity = BLOCKER
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
.rule = require.test-patterns-specified
|
|
2
|
+
|
|
3
|
+
.what = blueprints must specify test patterns for integration and acceptance tests
|
|
4
|
+
|
|
5
|
+
.why = clear test patterns enable fast feedback loops and thorough verification; without patterns, tests become inconsistent and unreliable
|
|
6
|
+
|
|
7
|
+
.how = verify test patterns are articulated (given/when/then structure, fixtures, mocks vs real, isolation strategy); check that patterns support rapid iteration
|
|
8
|
+
|
|
9
|
+
.examples:
|
|
10
|
+
.positive:
|
|
11
|
+
- |
|
|
12
|
+
## testing
|
|
13
|
+
|
|
14
|
+
### test patterns
|
|
15
|
+
|
|
16
|
+
**unit tests**
|
|
17
|
+
- pure function testing with mocked dependencies
|
|
18
|
+
- given/when/then structure via test-fns
|
|
19
|
+
|
|
20
|
+
**integration tests**
|
|
21
|
+
- real filesystem operations against .test/assets/example.repo/
|
|
22
|
+
- no mocking of bhrain invocation
|
|
23
|
+
- cleanup via afterEach hooks
|
|
24
|
+
|
|
25
|
+
**acceptance tests**
|
|
26
|
+
- black-box testing via CLI invocation
|
|
27
|
+
- verify file outputs exist and contain expected content
|
|
28
|
+
- use real behavior directory structure
|
|
29
|
+
.negative:
|
|
30
|
+
- |
|
|
31
|
+
## testing
|
|
32
|
+
|
|
33
|
+
**unit tests**
|
|
34
|
+
- test the functions
|
|
35
|
+
|
|
36
|
+
**integration tests**
|
|
37
|
+
- test the integrations
|
|
38
|
+
- |
|
|
39
|
+
## testing
|
|
40
|
+
|
|
41
|
+
we will use jest for testing.
|
|
42
|
+
|
|
43
|
+
.severity = BLOCKER
|
package/dist/domain.roles/behaver/briefs/practices/behavior.criteria/rule.prefer.dependency-order.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
.rule = prefer.dependency-order
|
|
2
|
+
|
|
3
|
+
.what = usecases should be ordered by dependency (foundational first)
|
|
4
|
+
|
|
5
|
+
.why = dependency order enables incremental verification and natural read flow; foundational behaviors must be validated before dependents; reduces debugging complexity
|
|
6
|
+
|
|
7
|
+
.how = verify that referenced behaviors appear before dependents; check that usecases can be implemented and tested in declared order
|
|
8
|
+
|
|
9
|
+
.examples:
|
|
10
|
+
.positive:
|
|
11
|
+
- |
|
|
12
|
+
# usecase.1 = rule briefs are discoverable
|
|
13
|
+
|
|
14
|
+
given('rule briefs exist')
|
|
15
|
+
when('searched')
|
|
16
|
+
then('found at expected paths')
|
|
17
|
+
|
|
18
|
+
# usecase.2 = single artifact review (depends on usecase.1)
|
|
19
|
+
|
|
20
|
+
given('a wish document exists')
|
|
21
|
+
when('reviewed with rules from usecase.1')
|
|
22
|
+
then('feedback produced')
|
|
23
|
+
|
|
24
|
+
# usecase.3 = composite review (depends on usecase.2)
|
|
25
|
+
|
|
26
|
+
given('behavior directory exists')
|
|
27
|
+
when('review.behavior invoked')
|
|
28
|
+
then('invokes single artifact review from usecase.2')
|
|
29
|
+
.negative:
|
|
30
|
+
- |
|
|
31
|
+
# usecase.1 = composite review (depends on undefined behaviors)
|
|
32
|
+
|
|
33
|
+
given('review.behavior invoked')
|
|
34
|
+
when('executed')
|
|
35
|
+
then('invokes single artifact review')
|
|
36
|
+
|
|
37
|
+
# usecase.2 = single artifact review (should come first)
|
|
38
|
+
|
|
39
|
+
given('a wish exists')
|
|
40
|
+
when('reviewed')
|
|
41
|
+
then('feedback produced')
|
|
42
|
+
|
|
43
|
+
.severity = NITPICK
|
package/dist/domain.roles/behaver/briefs/practices/behavior.criteria/rule.prefer.depth-groups.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
.rule = prefer.depth-groups
|
|
2
|
+
|
|
3
|
+
.what = criteria should be grouped by depth of abstraction (foundation to contract)
|
|
4
|
+
|
|
5
|
+
.why = depth groups clarify the layer at which each behavior operates; enables progressive verification from low-level to high-level; foundation behaviors must work before contract behaviors can be tested
|
|
6
|
+
|
|
7
|
+
.how = check for depth progression from foundational usecases (infrastructure, data, internal logic) to contract usecases (api, user-facing, integration); verify low-level behaviors are declared before high-level dependents
|
|
8
|
+
|
|
9
|
+
.examples:
|
|
10
|
+
.positive:
|
|
11
|
+
- |
|
|
12
|
+
# usecase.1 = rule briefs are discoverable (foundation)
|
|
13
|
+
|
|
14
|
+
given('rule briefs exist')
|
|
15
|
+
when('searched by artifact type')
|
|
16
|
+
then('rules are found under expected paths')
|
|
17
|
+
|
|
18
|
+
# usecase.2 = reviewing a single artifact (internal)
|
|
19
|
+
|
|
20
|
+
given('a wish document exists')
|
|
21
|
+
when('reviewed with wish rules')
|
|
22
|
+
then('feedback is produced')
|
|
23
|
+
|
|
24
|
+
# usecase.3 = composite skill orchestrates full review (contract)
|
|
25
|
+
|
|
26
|
+
given('a behavior directory exists')
|
|
27
|
+
when('review.behavior skill is invoked')
|
|
28
|
+
then('all artifacts are reviewed')
|
|
29
|
+
then('feedback is aggregated')
|
|
30
|
+
.negative:
|
|
31
|
+
- |
|
|
32
|
+
# usecase.1 = full behavior review (contract first - wrong order)
|
|
33
|
+
|
|
34
|
+
given('review.behavior is invoked')
|
|
35
|
+
when('executed')
|
|
36
|
+
then('all feedback produced')
|
|
37
|
+
|
|
38
|
+
# usecase.2 = single artifact review (foundation after contract)
|
|
39
|
+
|
|
40
|
+
given('a wish exists')
|
|
41
|
+
when('reviewed')
|
|
42
|
+
then('feedback produced')
|
|
43
|
+
|
|
44
|
+
.severity = NITPICK
|
package/dist/domain.roles/behaver/briefs/practices/behavior.criteria/rule.prefer.usecase-groups.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
.rule = prefer.usecase-groups
|
|
2
|
+
|
|
3
|
+
.what = criteria should be grouped by usecase with `# usecase.N = description` headers
|
|
4
|
+
|
|
5
|
+
.why = usecase groups improve readability and navigation; related behaviors are reviewed together; enables systematic coverage verification
|
|
6
|
+
|
|
7
|
+
.how = check for usecase headers preceding related given blocks; verify each usecase has a descriptive title
|
|
8
|
+
|
|
9
|
+
.examples:
|
|
10
|
+
.positive:
|
|
11
|
+
- |
|
|
12
|
+
# usecase.1 = reviewing a wish document
|
|
13
|
+
|
|
14
|
+
given('a wish document exists')
|
|
15
|
+
when('reviewed with wish rules')
|
|
16
|
+
then('feedback identifies unclear desires')
|
|
17
|
+
|
|
18
|
+
given('a wish has unclear desires')
|
|
19
|
+
when('reviewed with wish rules')
|
|
20
|
+
then('feedback flags as BLOCKER')
|
|
21
|
+
|
|
22
|
+
# usecase.2 = reviewing a criteria document
|
|
23
|
+
|
|
24
|
+
given('a criteria document exists')
|
|
25
|
+
when('reviewed with criteria rules')
|
|
26
|
+
then('feedback verifies bdd format')
|
|
27
|
+
.negative:
|
|
28
|
+
- |
|
|
29
|
+
given('a wish document exists')
|
|
30
|
+
when('reviewed')
|
|
31
|
+
then('feedback provided')
|
|
32
|
+
|
|
33
|
+
given('a criteria document exists')
|
|
34
|
+
when('reviewed')
|
|
35
|
+
then('feedback provided')
|
|
36
|
+
|
|
37
|
+
given('a wish has unclear desires')
|
|
38
|
+
when('reviewed')
|
|
39
|
+
then('flagged')
|
|
40
|
+
|
|
41
|
+
.severity = NITPICK
|
package/dist/domain.roles/behaver/briefs/practices/behavior.criteria/rule.require.bdd-format.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
.rule = require.bdd-format
|
|
2
|
+
|
|
3
|
+
.what = criteria must use given/when/then/sothat format
|
|
4
|
+
|
|
5
|
+
.why = bdd format ensures criteria are structured, testable, and machine-parseable; prose-style requirements are ambiguous and hard to verify
|
|
6
|
+
|
|
7
|
+
.how = verify each usecase has given(), when(), then() declarations; check that sothat() explains the business value
|
|
8
|
+
|
|
9
|
+
.examples:
|
|
10
|
+
.positive:
|
|
11
|
+
- |
|
|
12
|
+
given('a wish document exists')
|
|
13
|
+
when('reviewed with wish rules')
|
|
14
|
+
then('feedback identifies unclear desires')
|
|
15
|
+
sothat('ambiguous wishes are caught early')
|
|
16
|
+
.negative:
|
|
17
|
+
- |
|
|
18
|
+
The system should review wish documents and provide feedback
|
|
19
|
+
when they have unclear desires so that ambiguous wishes are caught.
|
|
20
|
+
- |
|
|
21
|
+
- review wish documents
|
|
22
|
+
- provide feedback on unclear desires
|
|
23
|
+
- catch ambiguous wishes
|
|
24
|
+
|
|
25
|
+
.severity = BLOCKER
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
.rule = prefer.clear-deliverables
|
|
2
|
+
|
|
3
|
+
.what = each phase should have clear, measurable deliverables
|
|
4
|
+
|
|
5
|
+
.why = clear deliverables enable progress track and completion verification; vague deliverables lead to unclear done-ness
|
|
6
|
+
|
|
7
|
+
.how = check each phase has explicit deliverable statements; verify deliverables are concrete and verifiable
|
|
8
|
+
|
|
9
|
+
.examples:
|
|
10
|
+
.positive:
|
|
11
|
+
- |
|
|
12
|
+
## phase.1 = rule briefs
|
|
13
|
+
|
|
14
|
+
### deliverables
|
|
15
|
+
- [ ] all 12 rule briefs fully implemented with content
|
|
16
|
+
|
|
17
|
+
### acceptance criteria
|
|
18
|
+
```
|
|
19
|
+
given('phase.1 is complete')
|
|
20
|
+
when('cat any rule file in behavior.wish/')
|
|
21
|
+
then('.what, .why, .how sections have content')
|
|
22
|
+
then('.examples.positive has at least one example')
|
|
23
|
+
then('.severity is set to BLOCKER or NITPICK')
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### verification
|
|
27
|
+
```sh
|
|
28
|
+
for f in src/domain.roles/behaver/briefs/practices/behavior.*/rule.*.md; do
|
|
29
|
+
grep -c ".what\|.why\|.how" "$f"
|
|
30
|
+
done
|
|
31
|
+
```
|
|
32
|
+
.negative:
|
|
33
|
+
- |
|
|
34
|
+
## phase.1 = rule briefs
|
|
35
|
+
|
|
36
|
+
implement the rule briefs.
|
|
37
|
+
- |
|
|
38
|
+
## phase.1 = rule briefs
|
|
39
|
+
|
|
40
|
+
### tasks
|
|
41
|
+
- write the rules
|
|
42
|
+
- make them good
|
|
43
|
+
|
|
44
|
+
(no explicit deliverables or verification)
|
|
45
|
+
|
|
46
|
+
.severity = NITPICK
|