Files
Claude-Code-Workflow/.claude/skills/workflow-skill-designer/phases/04-validation.md
catlog22 47c192f584 Add orchestrator design, phase file generation, and validation processes
- Implement Phase 2: Orchestrator Design with detailed steps for generating SKILL.md
- Introduce Phase 3: Phase Files Design to create phase files with content fidelity
- Establish Phase 4: Validation & Integration to ensure structural completeness and reference integrity
- Include comprehensive validation checks for content quality and data flow consistency
- Enhance documentation with clear objectives and critical rules for each phase
2026-02-05 19:29:45 +08:00

398 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 4: Validation & Integration
Validate the generated skill package for structural completeness, reference integrity, and content quality. Produce a validation report and integration summary.
## Objective
- Verify all required files exist
- Validate SKILL.md references match actual phase files
- Check content preservation (for command extraction source)
- Verify cross-phase data flow consistency
- Report validation results to user
## Step 4.1: Structural Validation
```javascript
function validateStructure(config) {
const skillDir = `.claude/skills/${config.skillName}`;
const results = { errors: [], warnings: [], info: [] };
// Check SKILL.md exists
const skillMdExists = fileExists(`${skillDir}/SKILL.md`);
if (!skillMdExists) {
results.errors.push('SKILL.md not found');
}
// Check all phase files exist
for (const phase of config.phases) {
const filename = `${String(phase.number).padStart(2, '0')}-${phase.slug}.md`;
const filepath = `${skillDir}/phases/${filename}`;
if (!fileExists(filepath)) {
results.errors.push(`Phase file missing: ${filepath}`);
}
}
// Check SKILL.md frontmatter
if (skillMdExists) {
const skillMd = Read(`${skillDir}/SKILL.md`);
const fm = extractYAMLFrontmatter(skillMd);
if (!fm.name) results.errors.push('Frontmatter missing: name');
if (!fm.description) results.errors.push('Frontmatter missing: description');
if (!fm['allowed-tools']) results.errors.push('Frontmatter missing: allowed-tools');
// Check description has trigger phrase
if (fm.description && !fm.description.includes('Triggers on')) {
results.warnings.push('Description missing trigger phrase (Triggers on "...")');
}
}
return results;
}
```
## Step 4.2: Reference Integrity
```javascript
function validateReferences(config) {
const skillDir = `.claude/skills/${config.skillName}`;
const results = { errors: [], warnings: [], info: [] };
const skillMd = Read(`${skillDir}/SKILL.md`);
// Extract all Ref: markers from SKILL.md
const refMarkers = skillMd.match(/Ref: phases\/\S+\.md/g) || [];
const linkedFiles = skillMd.match(/\[phases\/\S+\.md\]\(phases\/\S+\.md\)/g) || [];
// Collect all referenced phase files
const referencedFiles = new Set();
for (const ref of refMarkers) {
referencedFiles.add(ref.replace('Ref: ', ''));
}
for (const link of linkedFiles) {
const match = link.match(/\(phases\/\S+\.md\)/);
if (match) referencedFiles.add(match[0].replace(/[()]/g, ''));
}
// Check each referenced file exists
for (const refFile of referencedFiles) {
if (!fileExists(`${skillDir}/${refFile}`)) {
results.errors.push(`Referenced file not found: ${refFile}`);
}
}
// Check each phase file is referenced in SKILL.md
for (const phase of config.phases) {
const filename = `phases/${String(phase.number).padStart(2, '0')}-${phase.slug}.md`;
if (!referencedFiles.has(filename)) {
results.warnings.push(`Phase file not referenced in SKILL.md: ${filename}`);
}
}
// Check Phase Reference Documents table exists
if (!skillMd.includes('Phase Reference Documents')) {
results.errors.push('SKILL.md missing Phase Reference Documents table');
}
// Check Phase Reference Documents table has entries for all phases
for (const phase of config.phases) {
const filename = `${String(phase.number).padStart(2, '0')}-${phase.slug}.md`;
if (!skillMd.includes(filename)) {
results.errors.push(`Phase Reference table missing entry for: ${filename}`);
}
}
return results;
}
```
## Step 4.3: Content Quality (Command Extraction Only)
```javascript
function validateContentQuality(config) {
const skillDir = `.claude/skills/${config.skillName}`;
const results = { errors: [], warnings: [], info: [] };
if (config.source.type !== 'command_set') {
results.info.push('Content quality check skipped (not command extraction)');
return results;
}
for (const phase of config.phases) {
if (!phase.sourcePath) continue;
const sourceContent = Read(phase.sourcePath);
const sourceBody = removeYAMLFrontmatter(sourceContent);
const filename = `${String(phase.number).padStart(2, '0')}-${phase.slug}.md`;
const phaseContent = Read(`${skillDir}/phases/${filename}`);
// Line count comparison
const sourceLines = sourceBody.split('\n').length;
const phaseLines = phaseContent.split('\n').length;
const ratio = phaseLines / sourceLines;
if (ratio < 0.7) {
results.errors.push(
`Phase ${phase.number} content loss: source=${sourceLines} lines, phase=${phaseLines} lines (${Math.round(ratio * 100)}%)`
);
} else if (ratio < 0.9) {
results.warnings.push(
`Phase ${phase.number} possible content reduction: source=${sourceLines}, phase=${phaseLines} (${Math.round(ratio * 100)}%)`
);
} else {
results.info.push(
`Phase ${phase.number} content preserved: source=${sourceLines}, phase=${phaseLines} (${Math.round(ratio * 100)}%)`
);
}
// Code block count comparison
const sourceBlocks = (sourceBody.match(/```/g) || []).length / 2;
const phaseBlocks = (phaseContent.match(/```/g) || []).length / 2;
if (phaseBlocks < sourceBlocks) {
results.warnings.push(
`Phase ${phase.number} missing code blocks: source=${sourceBlocks}, phase=${phaseBlocks}`
);
}
// Agent prompt preservation
const sourceAgents = (sourceBody.match(/Task\(|subagent_type/g) || []).length;
const phaseAgents = (phaseContent.match(/Task\(|subagent_type/g) || []).length;
if (phaseAgents < sourceAgents) {
results.errors.push(
`Phase ${phase.number} missing agent calls: source=${sourceAgents}, phase=${phaseAgents}`
);
}
}
return results;
}
```
## Step 4.4: Data Flow Consistency
```javascript
function validateDataFlow(config) {
const skillDir = `.claude/skills/${config.skillName}`;
const results = { errors: [], warnings: [], info: [] };
const skillMd = Read(`${skillDir}/SKILL.md`);
// Check all data flow variables are mentioned in SKILL.md
for (const flow of config.dataFlow) {
for (const variable of flow.variables) {
if (!skillMd.includes(variable)) {
results.warnings.push(
`Data flow variable '${variable}' (${flow.from}${flow.to}) not found in SKILL.md`
);
}
}
}
// Check conditional phases have their condition in SKILL.md
for (const phase of config.phases) {
if (phase.isConditional && phase.condition) {
// Extract the key variable from condition
const condVar = phase.condition.match(/\w+/)?.[0];
if (condVar && !skillMd.includes(condVar)) {
results.errors.push(
`Conditional Phase ${phase.number} condition variable '${condVar}' not found in SKILL.md`
);
}
}
}
return results;
}
```
## Step 4.5: SKILL.md Section Completeness
```javascript
function validateSkillMdSections(config) {
const skillDir = `.claude/skills/${config.skillName}`;
const results = { errors: [], warnings: [], info: [] };
const skillMd = Read(`${skillDir}/SKILL.md`);
// Required sections
const requiredSections = [
{ name: 'Architecture Overview', pattern: /## Architecture Overview/ },
{ name: 'Execution Flow', pattern: /## Execution Flow/ },
{ name: 'Core Rules', pattern: /## Core Rules/ },
{ name: 'Data Flow', pattern: /## Data Flow/ },
{ name: 'Error Handling', pattern: /## Error Handling/ }
];
// Recommended sections
const recommendedSections = [
{ name: 'Key Design Principles', pattern: /## Key Design Principles/ },
{ name: 'Input Processing', pattern: /## Input Processing/ },
{ name: 'TodoWrite Pattern', pattern: /## TodoWrite Pattern/ },
{ name: 'Coordinator Checklist', pattern: /## Coordinator Checklist/ },
{ name: 'Related Commands', pattern: /## Related Commands/ }
];
// Conditional sections
const conditionalSections = [
{ name: 'Auto Mode', pattern: /## Auto Mode/, condition: config.features.hasAutoMode },
{ name: 'Post-Phase Updates', pattern: /## Post-Phase Updates/, condition: config.features.hasPostPhaseUpdates }
];
for (const section of requiredSections) {
if (!section.pattern.test(skillMd)) {
results.errors.push(`Missing required section: ${section.name}`);
}
}
for (const section of recommendedSections) {
if (!section.pattern.test(skillMd)) {
results.warnings.push(`Missing recommended section: ${section.name}`);
}
}
for (const section of conditionalSections) {
if (section.condition && !section.pattern.test(skillMd)) {
results.warnings.push(`Missing conditional section: ${section.name} (feature enabled but section absent)`);
}
}
return results;
}
```
## Step 4.6: Aggregate Results and Report
```javascript
function generateValidationReport(config) {
const structural = validateStructure(config);
const references = validateReferences(config);
const content = validateContentQuality(config);
const dataFlow = validateDataFlow(config);
const sections = validateSkillMdSections(config);
// Aggregate
const allErrors = [
...structural.errors,
...references.errors,
...content.errors,
...dataFlow.errors,
...sections.errors
];
const allWarnings = [
...structural.warnings,
...references.warnings,
...content.warnings,
...dataFlow.warnings,
...sections.warnings
];
const allInfo = [
...structural.info,
...references.info,
...content.info,
...dataFlow.info,
...sections.info
];
// Quality gate
const gate = allErrors.length === 0 ? 'PASS' :
allErrors.length <= 2 ? 'REVIEW' : 'FAIL';
// Display report
const skillDir = `.claude/skills/${config.skillName}`;
console.log(`
╔══════════════════════════════════════╗
║ Workflow Skill Validation Report ║
╠══════════════════════════════════════╣
║ Skill: ${config.skillName.padEnd(28)}
║ Gate: ${gate.padEnd(28)}
╚══════════════════════════════════════╝
Structure:
${skillDir}/
├── SKILL.md ${fileExists(`${skillDir}/SKILL.md`) ? '✓' : '✗'}
└── phases/
${config.phases.map(p => {
const fn = `${String(p.number).padStart(2, '0')}-${p.slug}.md`;
return ` ├── ${fn.padEnd(30)} ${fileExists(`${skillDir}/phases/${fn}`) ? '✓' : '✗'}`;
}).join('\n')}
${allErrors.length > 0 ? `Errors (${allErrors.length}):\n${allErrors.map(e => `${e}`).join('\n')}` : 'Errors: None ✓'}
${allWarnings.length > 0 ? `Warnings (${allWarnings.length}):\n${allWarnings.map(w => `${w}`).join('\n')}` : 'Warnings: None ✓'}
${allInfo.length > 0 ? `Info:\n${allInfo.map(i => ` ${i}`).join('\n')}` : ''}
`);
return { gate, errors: allErrors, warnings: allWarnings, info: allInfo };
}
```
## Step 4.7: Error Recovery
If validation fails, offer recovery options:
```javascript
if (report.gate === 'FAIL') {
const recovery = AskUserQuestion({
questions: [{
question: `Validation found ${report.errors.length} errors. How to proceed?`,
header: "Recovery",
multiSelect: false,
options: [
{ label: "Auto-fix", description: "Attempt automatic fixes for common issues" },
{ label: "Regenerate phases", description: "Re-run Phase 3 with stricter preservation" },
{ label: "Accept as-is", description: "Proceed despite errors (manual fix later)" }
]
}]
});
if (recovery === 'Auto-fix') {
// Common auto-fixes:
// 1. Missing Next Phase links → add them
// 2. Missing Output sections → add from config
// 3. Missing Phase Reference table → generate from config
autoFixCommonIssues(config, report.errors);
// Re-validate
return generateValidationReport(config);
}
}
```
## Step 4.8: Integration Summary
```javascript
function displayIntegrationSummary(config) {
console.log(`
Integration Complete:
Location: .claude/skills/${config.skillName}/
Files: ${config.phases.length + 1} (SKILL.md + ${config.phases.length} phases)
Usage:
Trigger: ${config.triggers.map(t => `"${t}"`).join(', ')}
Auto: /${config.triggers[0]} --yes "task description"
Design Patterns Applied:
✓ Progressive phase loading (Ref: markers)
✓ Phase Reference Documents table
${config.features.hasTodoWriteSubTasks ? '✓' : '○'} TodoWrite attachment/collapse
${config.features.hasConditionalPhases ? '✓' : '○'} Conditional phase execution
${config.features.hasAutoMode ? '✓' : '○'} Auto mode (--yes flag)
${config.features.hasPostPhaseUpdates ? '✓' : '○'} Post-phase state updates
${config.features.hasPlanningNotes ? '✓' : '○'} Accumulated planning notes
Next Steps:
1. Review SKILL.md orchestrator logic
2. Review each phase file for completeness
3. Test skill invocation: /${config.triggers[0]} "test task"
4. Iterate based on execution results
`);
}
```
## Output
- **Report**: Validation results with quality gate (PASS/REVIEW/FAIL)
- **TodoWrite**: Mark Phase 4 completed (all tasks done)
## Completion
Workflow Skill Designer has completed. The generated skill package is ready at `.claude/skills/{skillName}/`.