@hstm-labs/forge-verifier 0.1.11
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/README.md +48 -0
- package/dist/compliance-builder.d.ts +26 -0
- package/dist/compliance-builder.d.ts.map +1 -0
- package/dist/compliance-builder.js +52 -0
- package/dist/compliance-builder.js.map +1 -0
- package/dist/coverage-calculator.d.ts +22 -0
- package/dist/coverage-calculator.d.ts.map +1 -0
- package/dist/coverage-calculator.js +29 -0
- package/dist/coverage-calculator.js.map +1 -0
- package/dist/criteria-extractor.d.ts +39 -0
- package/dist/criteria-extractor.d.ts.map +1 -0
- package/dist/criteria-extractor.js +93 -0
- package/dist/criteria-extractor.js.map +1 -0
- package/dist/formatters.d.ts +25 -0
- package/dist/formatters.d.ts.map +1 -0
- package/dist/formatters.js +84 -0
- package/dist/formatters.js.map +1 -0
- package/dist/gap-detector.d.ts +21 -0
- package/dist/gap-detector.d.ts.map +1 -0
- package/dist/gap-detector.js +73 -0
- package/dist/gap-detector.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/requirement-mapper.d.ts +21 -0
- package/dist/requirement-mapper.d.ts.map +1 -0
- package/dist/requirement-mapper.js +220 -0
- package/dist/requirement-mapper.js.map +1 -0
- package/dist/review-incorporator.d.ts +20 -0
- package/dist/review-incorporator.d.ts.map +1 -0
- package/dist/review-incorporator.js +33 -0
- package/dist/review-incorporator.js.map +1 -0
- package/dist/tech-stack-resolver.d.ts +45 -0
- package/dist/tech-stack-resolver.d.ts.map +1 -0
- package/dist/tech-stack-resolver.js +65 -0
- package/dist/tech-stack-resolver.js.map +1 -0
- package/dist/test-gen-types.d.ts +55 -0
- package/dist/test-gen-types.d.ts.map +1 -0
- package/dist/test-gen-types.js +8 -0
- package/dist/test-gen-types.js.map +1 -0
- package/dist/test-generate-stage.d.ts +52 -0
- package/dist/test-generate-stage.d.ts.map +1 -0
- package/dist/test-generate-stage.js +190 -0
- package/dist/test-generate-stage.js.map +1 -0
- package/dist/test-output-validator.d.ts +40 -0
- package/dist/test-output-validator.d.ts.map +1 -0
- package/dist/test-output-validator.js +171 -0
- package/dist/test-output-validator.js.map +1 -0
- package/dist/types.d.ts +94 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/verify-stage.d.ts +48 -0
- package/dist/verify-stage.d.ts.map +1 -0
- package/dist/verify-stage.js +155 -0
- package/dist/verify-stage.js.map +1 -0
- package/package.json +32 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VerifyStage — pipeline stage that verifies compliance of generated
|
|
3
|
+
* artifacts against specification requirements.
|
|
4
|
+
*
|
|
5
|
+
* This stage does NOT require an LLM. It runs after the review stage
|
|
6
|
+
* and produces a {@link ComplianceReport} with requirement coverage,
|
|
7
|
+
* gap analysis, and review finding incorporation.
|
|
8
|
+
*/
|
|
9
|
+
import { join, dirname } from 'node:path';
|
|
10
|
+
import { writeFileSync, mkdirSync } from 'node:fs';
|
|
11
|
+
import { ForgeError, ErrorCodes, hashContent } from '@hstm-labs/forge-common';
|
|
12
|
+
import { loadProfile } from '@hstm-labs/forge-profiles';
|
|
13
|
+
import { getOpinionatedStacks } from './tech-stack-resolver.js';
|
|
14
|
+
import { resolveTechStack } from './tech-stack-resolver.js';
|
|
15
|
+
import { mapRequirementsToArtifacts } from './requirement-mapper.js';
|
|
16
|
+
import { calculateCoverage } from './coverage-calculator.js';
|
|
17
|
+
import { detectGaps } from './gap-detector.js';
|
|
18
|
+
import { incorporateReviewFindings } from './review-incorporator.js';
|
|
19
|
+
import { buildComplianceReport } from './compliance-builder.js';
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Stage
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
/**
|
|
24
|
+
* Pipeline stage that verifies spec-to-artifact compliance.
|
|
25
|
+
*
|
|
26
|
+
* Produces a {@link ComplianceReport} with requirement mapping, coverage
|
|
27
|
+
* scoring, gap analysis, and review finding incorporation. The report is
|
|
28
|
+
* written as `compliance-report.json` and stored in `data.compliance`.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* const stage = new VerifyStage();
|
|
33
|
+
* const output = await stage.execute(input, context);
|
|
34
|
+
* const report = output.data?.compliance as ComplianceReport;
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export class VerifyStage {
|
|
38
|
+
name = 'verify';
|
|
39
|
+
dependsOn = ['review'];
|
|
40
|
+
requiresLLM = false;
|
|
41
|
+
/**
|
|
42
|
+
* Execute the compliance verification stage.
|
|
43
|
+
*
|
|
44
|
+
* @param input - Input from prior stages (keyed by stage name)
|
|
45
|
+
* @param context - Pipeline context with config, workspace, and runId
|
|
46
|
+
* @returns Stage output with compliance report artifact and ComplianceReport in data
|
|
47
|
+
* @throws {ForgeError} FORGE-PIPE-001 if validate stage output is missing
|
|
48
|
+
*/
|
|
49
|
+
async execute(input, context) {
|
|
50
|
+
// 1. Get parsed spec from validate stage
|
|
51
|
+
const validateOutput = input['validate'];
|
|
52
|
+
if (validateOutput === undefined) {
|
|
53
|
+
throw new ForgeError(ErrorCodes.PIPE.STAGE_FAILURE, "Verify stage requires 'validate' stage output, but it was not found. " +
|
|
54
|
+
'Ensure the validate stage runs before the verify stage.');
|
|
55
|
+
}
|
|
56
|
+
const parsedSpec = validateOutput.data?.['parsedSpec'];
|
|
57
|
+
if (parsedSpec === undefined) {
|
|
58
|
+
throw new ForgeError(ErrorCodes.PIPE.STAGE_FAILURE, 'Validate stage did not produce a parsed specification in its output data.');
|
|
59
|
+
}
|
|
60
|
+
// 2. Collect all generation stage outputs
|
|
61
|
+
const generationOutputs = this.collectGenerationOutputs(input);
|
|
62
|
+
// 3. Get review report (optional — may be undefined if review was skipped)
|
|
63
|
+
const reviewReport = input['review']?.data?.['review'];
|
|
64
|
+
// 4. Map requirements to artifacts
|
|
65
|
+
const coverageResults = mapRequirementsToArtifacts(parsedSpec.requirements, parsedSpec.entities, generationOutputs);
|
|
66
|
+
// 5. Calculate coverage score
|
|
67
|
+
const { score, coveredCount, totalCount } = calculateCoverage(coverageResults);
|
|
68
|
+
// 6. Detect gaps
|
|
69
|
+
const gaps = detectGaps(coverageResults, parsedSpec.requirements);
|
|
70
|
+
// 7. Incorporate review findings
|
|
71
|
+
const reviewFindings = incorporateReviewFindings(reviewReport);
|
|
72
|
+
// 8. Resolve API type and tech stack (when spec does not define them)
|
|
73
|
+
const profile = loadProfile(context.config.profileName, context.workspace.rootDir);
|
|
74
|
+
const techResolution = resolveTechStack(parsedSpec, context.config, profile);
|
|
75
|
+
const stacksList = getOpinionatedStacks().map((s) => ({
|
|
76
|
+
id: s.id,
|
|
77
|
+
label: s.label,
|
|
78
|
+
apiType: s.apiType,
|
|
79
|
+
description: s.description,
|
|
80
|
+
}));
|
|
81
|
+
// 9. Build compliance report
|
|
82
|
+
const report = buildComplianceReport({
|
|
83
|
+
runId: context.runId,
|
|
84
|
+
coverage: coverageResults,
|
|
85
|
+
gaps,
|
|
86
|
+
reviewFindings,
|
|
87
|
+
totalRequirements: totalCount,
|
|
88
|
+
coveredRequirements: coveredCount,
|
|
89
|
+
score,
|
|
90
|
+
});
|
|
91
|
+
// 10. Write compliance-report.json and tech-stack-resolution.json to output directory
|
|
92
|
+
const outputDir = join(context.workspace.forgeDir, 'runs', context.runId, 'stages', 'verify', 'artifacts');
|
|
93
|
+
const reportJson = JSON.stringify(report, null, 2);
|
|
94
|
+
const reportPath = 'compliance-report.json';
|
|
95
|
+
const fullPath = join(outputDir, reportPath);
|
|
96
|
+
mkdirSync(dirname(fullPath), { recursive: true });
|
|
97
|
+
writeFileSync(fullPath, reportJson, 'utf-8');
|
|
98
|
+
const techResolutionPayload = {
|
|
99
|
+
resolvedApiType: techResolution.resolvedApiType,
|
|
100
|
+
resolvedTechStack: techResolution.resolvedTechStack,
|
|
101
|
+
clarificationSuggested: techResolution.clarificationSuggested,
|
|
102
|
+
suggestedConfigSnippet: techResolution.suggestedConfigSnippet,
|
|
103
|
+
opinionatedStacks: stacksList,
|
|
104
|
+
};
|
|
105
|
+
const techResolutionJson = JSON.stringify(techResolutionPayload, null, 2);
|
|
106
|
+
const techResolutionPath = 'tech-stack-resolution.json';
|
|
107
|
+
writeFileSync(join(outputDir, techResolutionPath), techResolutionJson, 'utf-8');
|
|
108
|
+
const artifacts = [
|
|
109
|
+
{
|
|
110
|
+
filePath: reportPath,
|
|
111
|
+
content: reportJson,
|
|
112
|
+
contentHash: hashContent(reportJson),
|
|
113
|
+
sizeBytes: Buffer.byteLength(reportJson, 'utf-8'),
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
filePath: techResolutionPath,
|
|
117
|
+
content: techResolutionJson,
|
|
118
|
+
contentHash: hashContent(techResolutionJson),
|
|
119
|
+
sizeBytes: Buffer.byteLength(techResolutionJson, 'utf-8'),
|
|
120
|
+
},
|
|
121
|
+
];
|
|
122
|
+
// 11. Return stage output
|
|
123
|
+
return {
|
|
124
|
+
artifacts,
|
|
125
|
+
data: {
|
|
126
|
+
compliance: report,
|
|
127
|
+
resolvedApiType: techResolution.resolvedApiType,
|
|
128
|
+
resolvedTechStack: techResolution.resolvedTechStack,
|
|
129
|
+
clarificationSuggested: techResolution.clarificationSuggested,
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// -------------------------------------------------------------------------
|
|
134
|
+
// Private helpers
|
|
135
|
+
// -------------------------------------------------------------------------
|
|
136
|
+
/**
|
|
137
|
+
* Collect generation stage outputs from pipeline input.
|
|
138
|
+
*
|
|
139
|
+
* Gracefully handles missing stages — each output is optional.
|
|
140
|
+
*
|
|
141
|
+
* @param input - Pipeline stage input map
|
|
142
|
+
* @returns Collected generation stage outputs
|
|
143
|
+
*/
|
|
144
|
+
collectGenerationOutputs(input) {
|
|
145
|
+
return {
|
|
146
|
+
architecture: input['architect']?.data?.['architecture'],
|
|
147
|
+
api: input['services-generate']?.data?.['api'],
|
|
148
|
+
ui: input['apps-generate']?.data?.['ui'],
|
|
149
|
+
infra: input['infra-generate']?.data?.['infra'],
|
|
150
|
+
security: input['security-generate']?.data?.['security'],
|
|
151
|
+
seedData: input['seed-data']?.data?.['seedData'],
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=verify-stage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-stage.js","sourceRoot":"","sources":["../src/verify-stage.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hstm-labs/forge-verifier",
|
|
3
|
+
"version": "0.1.11",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"test": "vitest run",
|
|
16
|
+
"prepublishOnly": "npm run build"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@hstm-labs/forge-common": "0.1.11",
|
|
20
|
+
"@hstm-labs/forge-core": "0.1.11",
|
|
21
|
+
"@hstm-labs/forge-architect": "0.1.11",
|
|
22
|
+
"@hstm-labs/forge-services-generator": "0.1.11",
|
|
23
|
+
"@hstm-labs/forge-apps-generator": "0.1.11",
|
|
24
|
+
"@hstm-labs/forge-infra-generator": "0.1.11",
|
|
25
|
+
"@hstm-labs/forge-security-generator": "0.1.11",
|
|
26
|
+
"@hstm-labs/forge-seed-data": "0.1.11",
|
|
27
|
+
"@hstm-labs/forge-reviewer": "0.1.11",
|
|
28
|
+
"@hstm-labs/forge-spec-parser": "0.1.11",
|
|
29
|
+
"@hstm-labs/forge-profiles": "0.1.11",
|
|
30
|
+
"@hstm-labs/forge-templates": "0.1.11"
|
|
31
|
+
}
|
|
32
|
+
}
|