chati-dev 4.3.1 → 4.4.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.
Files changed (147) hide show
  1. package/README.md +18 -13
  2. package/bin/chati.js +12 -4
  3. package/framework/agents/build/dev.md +5 -1
  4. package/framework/agents/discover/greenfield-wu.md +16 -1
  5. package/framework/agents/plan/tasks.md +31 -0
  6. package/framework/agents/plan/ux-brand-architect.md +21 -2
  7. package/framework/agents/plan/ux-component-engineer.md +10 -0
  8. package/framework/agents/quality/qa-implementation.md +1 -1
  9. package/framework/agents/quality/qa-planning.md +1 -1
  10. package/framework/agents/quality/qa-visual.md +24 -21
  11. package/framework/config.yaml +5 -4
  12. package/framework/constitution.md +58 -11
  13. package/framework/context/governance.md +12 -10
  14. package/framework/context/root.md +2 -2
  15. package/framework/data/entity-registry.yaml +12 -4
  16. package/framework/data/qa-rubrics.yaml +335 -0
  17. package/framework/domains/constitution.yaml +3 -3
  18. package/framework/executors/json-validate.js +80 -0
  19. package/framework/executors/npm-script.js +72 -0
  20. package/framework/executors/path-check.js +67 -0
  21. package/framework/executors/registry.yaml +36 -0
  22. package/framework/hooks/advance-trigger.js +47 -3
  23. package/framework/hooks/constitution-guard.js +9 -4
  24. package/framework/hooks/git-push-authority.js +113 -0
  25. package/framework/hooks/license-guard.js +59 -9
  26. package/framework/hooks/model-governance.js +40 -17
  27. package/framework/hooks/prism-engine.js +78 -11
  28. package/framework/hooks/session-digest.js +12 -3
  29. package/framework/hooks/settings.json +7 -3
  30. package/framework/hooks/style-guard.js +52 -3
  31. package/framework/hooks/team-quality-gate.js +43 -5
  32. package/framework/i18n/en.yaml +3 -3
  33. package/framework/i18n/es.yaml +3 -3
  34. package/framework/i18n/fr.yaml +3 -3
  35. package/framework/i18n/pt.yaml +3 -3
  36. package/framework/intelligence/confidence.yaml +85 -6
  37. package/framework/intelligence/context-engine.md +9 -5
  38. package/framework/intelligence/decision-engine.md +1 -1
  39. package/framework/orchestrator/chati-router.js +1 -1
  40. package/framework/orchestrator/chati-update.md +19 -3
  41. package/framework/orchestrator/chati.md +19 -1
  42. package/framework/quality-gates/planning-gate.md +2 -0
  43. package/framework/scaffold/motion-premium/scaffold.yaml +2 -1
  44. package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +1 -1
  45. package/framework/scaffold/saas-dashboard/README.md +58 -0
  46. package/framework/scaffold/saas-dashboard/app/dashboard/page.tsx.template +546 -0
  47. package/framework/scaffold/saas-dashboard/app/globals.css.template +746 -0
  48. package/framework/scaffold/saas-dashboard/app/layout.tsx.template +192 -0
  49. package/framework/scaffold/saas-dashboard/app/shell.css.template +1070 -0
  50. package/framework/scaffold/saas-dashboard/components/data/Chart.tsx.template +725 -0
  51. package/framework/scaffold/saas-dashboard/components/data/DataTable.tsx.template +623 -0
  52. package/framework/scaffold/saas-dashboard/components/data/DataTable.types.ts.template +104 -0
  53. package/framework/scaffold/saas-dashboard/components/data/DataTablePagination.tsx.template +234 -0
  54. package/framework/scaffold/saas-dashboard/components/data/SkeletonBlock.tsx.template +111 -0
  55. package/framework/scaffold/saas-dashboard/components/data/StatCard.tsx.template +393 -0
  56. package/framework/scaffold/saas-dashboard/components/data/StatCardGrid.tsx.template +121 -0
  57. package/framework/scaffold/saas-dashboard/components/feedback/EmptyState.tsx.template +281 -0
  58. package/framework/scaffold/saas-dashboard/components/interaction/CommandPalette.tsx.template +767 -0
  59. package/framework/scaffold/saas-dashboard/components/interaction/Field.tsx.template +351 -0
  60. package/framework/scaffold/saas-dashboard/components/interaction/Form.tsx.template +424 -0
  61. package/framework/scaffold/saas-dashboard/components/primitives/Badge.tsx.template +193 -0
  62. package/framework/scaffold/saas-dashboard/components/primitives/Button.tsx.template +261 -0
  63. package/framework/scaffold/saas-dashboard/components/primitives/Card.tsx.template +287 -0
  64. package/framework/scaffold/saas-dashboard/components/primitives/Input.tsx.template +310 -0
  65. package/framework/scaffold/saas-dashboard/components/primitives/Spinner.tsx.template +135 -0
  66. package/framework/scaffold/saas-dashboard/components/primitives/index.ts.template +60 -0
  67. package/framework/scaffold/saas-dashboard/components/shell/AppShell.tsx.template +174 -0
  68. package/framework/scaffold/saas-dashboard/components/shell/Breadcrumb.tsx.template +186 -0
  69. package/framework/scaffold/saas-dashboard/components/shell/Container.tsx.template +86 -0
  70. package/framework/scaffold/saas-dashboard/components/shell/NavItem.tsx.template +147 -0
  71. package/framework/scaffold/saas-dashboard/components/shell/Sidebar.tsx.template +378 -0
  72. package/framework/scaffold/saas-dashboard/components/shell/SidebarContext.tsx.template +169 -0
  73. package/framework/scaffold/saas-dashboard/components/shell/ThemeToggle.tsx.template +128 -0
  74. package/framework/scaffold/saas-dashboard/components/shell/Topbar.tsx.template +301 -0
  75. package/framework/scaffold/saas-dashboard/lib/brand.ts.template +324 -0
  76. package/framework/scaffold/saas-dashboard/scaffold.yaml +225 -0
  77. package/framework/schemas/session.schema.json +5 -0
  78. package/framework/schemas/task.schema.json +9 -0
  79. package/framework/scripts/visual-qa.js +87 -1
  80. package/framework/tasks/orchestrator-health.md +4 -4
  81. package/framework/tasks/qa-impl-verdict.md +11 -5
  82. package/framework/templates/qa-gate-tmpl.yaml +24 -11
  83. package/package.json +3 -3
  84. package/src/config/context-file-generator.js +0 -6
  85. package/src/dashboard/renderer.js +0 -36
  86. package/src/executors/runner.js +204 -0
  87. package/src/installer/core.js +2 -1
  88. package/src/installer/templates.js +5 -6
  89. package/src/intelligence/registry-manager.js +1 -1
  90. package/src/license/client.js +9 -3
  91. package/src/license/commands.js +12 -2
  92. package/src/license/machine-id.js +42 -1
  93. package/src/memory/gotchas.js +58 -40
  94. package/src/memory/magic-docs.js +1 -1
  95. package/src/memory/session-digest.js +9 -4
  96. package/src/orchestrator/cli.js +174 -14
  97. package/src/orchestrator/doctor.js +98 -16
  98. package/src/orchestrator/pipeline-manager.js +44 -22
  99. package/src/orchestrator/session-manager.js +56 -8
  100. package/src/telemetry/sender.js +7 -19
  101. package/src/terminal/run-team.js +3 -3
  102. package/src/upgrade/tracked-files-detector.js +34 -16
  103. package/src/utils/feature-flags.js +1 -1
  104. package/src/utils/flatten-entities.js +4 -40
  105. package/src/utils/schema-validator.js +0 -14
  106. package/src/wizard/i18n.js +3 -3
  107. package/src/api/index.js +0 -120
  108. package/src/autonomy/autonomous-gate.js +0 -294
  109. package/src/autonomy/build-loop.js +0 -281
  110. package/src/autonomy/build-state.js +0 -286
  111. package/src/autonomy/cause-analyzer.js +0 -177
  112. package/src/autonomy/escalation.js +0 -214
  113. package/src/autonomy/index.js +0 -51
  114. package/src/autonomy/mode-manager.js +0 -225
  115. package/src/autonomy/mode-suggester.js +0 -283
  116. package/src/autonomy/progress-reporter.js +0 -275
  117. package/src/autonomy/safety-net.js +0 -370
  118. package/src/config/agent-customizer.js +0 -231
  119. package/src/decision/analyzer.js +0 -291
  120. package/src/decision/engine.js +0 -250
  121. package/src/decision/index.js +0 -38
  122. package/src/decision/registry-healer.js +0 -468
  123. package/src/decision/registry-updater.js +0 -339
  124. package/src/extensions/loader.js +0 -145
  125. package/src/extensions/registry.js +0 -134
  126. package/src/gates/circuit-breaker.js +0 -151
  127. package/src/gates/g1-planning-complete.js +0 -154
  128. package/src/gates/g2-qa-planning.js +0 -156
  129. package/src/gates/g3-implementation.js +0 -215
  130. package/src/gates/g4-qa-implementation.js +0 -240
  131. package/src/gates/g5-deploy-ready.js +0 -181
  132. package/src/gates/gate-base.js +0 -185
  133. package/src/gates/index.js +0 -46
  134. package/src/health/auto-fix.js +0 -216
  135. package/src/health/engine.js +0 -246
  136. package/src/merger/semantic-merger.js +0 -292
  137. package/src/preview/detector.js +0 -238
  138. package/src/preview/index.js +0 -20
  139. package/src/preview/launcher.js +0 -235
  140. package/src/preview/log-buffer.js +0 -103
  141. package/src/quality/metrics-collector.js +0 -281
  142. package/src/quality/test-runner.js +0 -366
  143. package/src/tasks/executor.js +0 -195
  144. package/src/tasks/index.js +0 -4
  145. package/src/tasks/loader.js +0 -210
  146. package/src/tasks/router.js +0 -182
  147. package/src/utils/event-bus.js +0 -126
@@ -1,240 +0,0 @@
1
- /**
2
- * @fileoverview G4 — QA Implementation Gate
3
- *
4
- * Post-QA-Implementation gate — the most critical gate in the pipeline.
5
- * Validates that all tests pass, no critical bugs remain, performance
6
- * benchmarks are met, and security scans are clean.
7
- *
8
- * Verdicts:
9
- * PASS — All criteria met, score >= 95%
10
- * CONCERNS — Score 90-95%, minor issues noted
11
- * FAIL — Score < 90% or critical issues
12
- * WAIVED — Human explicitly overrode
13
- */
14
-
15
- import { existsSync, readFileSync } from 'node:fs';
16
- import { join } from 'node:path';
17
- import { resolveFrameworkDir } from '../utils/framework-dir.js';
18
- import { GateBase, determineVerdict } from './gate-base.js';
19
- import { loadSession } from '../orchestrator/session-manager.js';
20
- import { loadHandoff } from '../tasks/handoff.js';
21
-
22
- export const QA_IMPL_VERDICTS = {
23
- PASS: 'pass',
24
- CONCERNS: 'concerns',
25
- FAIL: 'fail',
26
- WAIVED: 'waived',
27
- };
28
-
29
- export class QAImplementationGate extends GateBase {
30
- constructor() {
31
- super({
32
- id: 'g4-qa-implementation',
33
- name: 'QA Implementation',
34
- pipelinePoint: 'post-qa-impl',
35
- agent: 'qa-implementation',
36
- });
37
- }
38
-
39
- /**
40
- * Collect evidence about QA implementation results.
41
- *
42
- * @param {string} projectDir
43
- * @returns {object} Evidence about test results, bugs, performance, security
44
- */
45
- _collectEvidence(projectDir) {
46
- const evidence = {
47
- qaImplHandoff: null,
48
- allTestCriteriaMet: false,
49
- noCriticalBugs: true,
50
- performanceBenchmarksMet: null, // null = not defined
51
- securityScanClean: null,
52
- sessionState: null,
53
- verdict: null,
54
- };
55
-
56
- // Load QA-Implementation handoff
57
- const handoffResult = loadHandoff(projectDir, 'qa-implementation');
58
- if (handoffResult.loaded && handoffResult.handoff) {
59
- const handoff = handoffResult.handoff;
60
- evidence.qaImplHandoff = {
61
- score: handoff.score,
62
- status: handoff.status,
63
- outputs: handoff.outputs || [],
64
- blockers: handoff.blockers || [],
65
- criteriaUnmet: handoff.criteria_unmet || [],
66
- criteriaMet: handoff.criteria_met || [],
67
- };
68
-
69
- evidence.allTestCriteriaMet = evidence.qaImplHandoff.criteriaUnmet.length === 0;
70
- evidence.noCriticalBugs = evidence.qaImplHandoff.blockers.length === 0;
71
- }
72
-
73
- // Check for performance benchmark results — parse content for real findings
74
- const perfPaths = [
75
- join(projectDir, resolveFrameworkDir(projectDir), 'artifacts', 'performance-report.md'),
76
- join(projectDir, '.performance-benchmark'),
77
- ];
78
- for (const perfPath of perfPaths) {
79
- if (existsSync(perfPath)) {
80
- try {
81
- const content = readFileSync(perfPath, 'utf-8');
82
- const hasFailures = /fail|exceeded|timeout|regression|degradation|below\s*threshold/i.test(content);
83
- const hasPassIndicator = /pass|met|within\s*budget|no\s*(regressions|issues)|acceptable/i.test(content);
84
- if (hasFailures && !hasPassIndicator) {
85
- evidence.performanceBenchmarksMet = false;
86
- } else if (hasPassIndicator) {
87
- evidence.performanceBenchmarksMet = true;
88
- } else {
89
- evidence.performanceBenchmarksMet = null; // Ambiguous
90
- }
91
- } catch { /* expected: file may not exist */
92
- evidence.performanceBenchmarksMet = null;
93
- }
94
- break;
95
- }
96
- }
97
-
98
- // Check for security scan — parse content for real findings
99
- const secPaths = [
100
- join(projectDir, resolveFrameworkDir(projectDir), 'artifacts', 'security-report.md'),
101
- join(projectDir, '.security-scan'),
102
- ];
103
- for (const secPath of secPaths) {
104
- if (existsSync(secPath)) {
105
- try {
106
- const content = readFileSync(secPath, 'utf-8').toLowerCase();
107
- // Look for indicators of security failures
108
- const hasBlockers = /blocker|critical|high\s*severity|vulnerability found|failed/i.test(content);
109
- const hasPassIndicator = /pass|clean|no\s*(issues|vulnerabilities|findings)|score:\s*(9[5-9]|100)/i.test(content);
110
- if (hasBlockers) {
111
- evidence.securityScanClean = false;
112
- } else if (hasPassIndicator) {
113
- evidence.securityScanClean = true;
114
- } else {
115
- // File exists but has no clear pass/fail indicators — ambiguous — not clean by default
116
- evidence.securityScanClean = null;
117
- }
118
- } catch { /* expected: operation may fail gracefully */
119
- // File exists but cannot be read — treat as not available
120
- evidence.securityScanClean = null;
121
- }
122
- break;
123
- }
124
- }
125
-
126
- // Load session state
127
- const sessionResult = loadSession(projectDir);
128
- if (sessionResult.loaded && sessionResult.session) {
129
- const qaAgent = sessionResult.session.agents?.['qa-implementation'];
130
- evidence.sessionState = {
131
- qaImplStatus: qaAgent?.status || 'pending',
132
- qaImplScore: qaAgent?.score || 0,
133
- completedAgents: sessionResult.session.completed_agents || [],
134
- };
135
- }
136
-
137
- // Determine verdict
138
- evidence.verdict = this._determineVerdict(evidence);
139
-
140
- return evidence;
141
- }
142
-
143
- /**
144
- * Determine the QA verdict based on evidence.
145
- *
146
- * @param {object} evidence
147
- * @returns {string} One of QA_IMPL_VERDICTS
148
- */
149
- _determineVerdict(evidence) {
150
- if (!evidence.qaImplHandoff) {
151
- return QA_IMPL_VERDICTS.FAIL;
152
- }
153
-
154
- const score = evidence.qaImplHandoff.score ?? 0;
155
-
156
- if (!evidence.noCriticalBugs) {
157
- return QA_IMPL_VERDICTS.FAIL;
158
- }
159
-
160
- if (score >= 95 && evidence.allTestCriteriaMet) {
161
- return QA_IMPL_VERDICTS.PASS;
162
- }
163
-
164
- if (score >= 90) {
165
- return QA_IMPL_VERDICTS.CONCERNS;
166
- }
167
-
168
- return QA_IMPL_VERDICTS.FAIL;
169
- }
170
-
171
- /**
172
- * Validate QA implementation evidence.
173
- *
174
- * @param {object} evidence
175
- * @returns {{ score: number, criteriaResults: string[], allCriteria: string[], warnings: string[] }}
176
- */
177
- _validateEvidence(evidence) {
178
- const allCriteria = [
179
- 'QA-Implementation handoff exists',
180
- 'All test criteria met',
181
- 'No critical bugs open',
182
- 'Performance benchmarks met',
183
- 'Security scan clean',
184
- 'QA-Implementation score >= 95',
185
- ];
186
-
187
- const criteriaResults = [];
188
- const warnings = [];
189
-
190
- // Check handoff exists
191
- if (evidence.qaImplHandoff) {
192
- criteriaResults.push('QA-Implementation handoff exists');
193
- }
194
-
195
- // Check test criteria
196
- if (evidence.allTestCriteriaMet) {
197
- criteriaResults.push('All test criteria met');
198
- } else if (evidence.qaImplHandoff) {
199
- warnings.push(`${evidence.qaImplHandoff.criteriaUnmet.length} test criteria unmet`);
200
- }
201
-
202
- // Check bugs
203
- if (evidence.noCriticalBugs) {
204
- criteriaResults.push('No critical bugs open');
205
- } else {
206
- warnings.push('Critical bugs remain open');
207
- }
208
-
209
- // Check performance
210
- if (evidence.performanceBenchmarksMet === true) {
211
- criteriaResults.push('Performance benchmarks met');
212
- } else if (evidence.performanceBenchmarksMet === null) {
213
- // Not defined is not a failure — just a warning
214
- warnings.push('Performance benchmarks not defined');
215
- }
216
-
217
- // Check security
218
- if (evidence.securityScanClean === true) {
219
- criteriaResults.push('Security scan clean');
220
- } else if (evidence.securityScanClean === null) {
221
- warnings.push('Security scan not found');
222
- }
223
-
224
- // Check score
225
- if (evidence.qaImplHandoff && evidence.qaImplHandoff.score >= 95) {
226
- criteriaResults.push('QA-Implementation score >= 95');
227
- } else if (evidence.qaImplHandoff) {
228
- warnings.push(`QA-Impl score: ${evidence.qaImplHandoff.score} (need >= 95)`);
229
- }
230
-
231
- const score = allCriteria.length > 0
232
- ? Math.round((criteriaResults.length / allCriteria.length) * 100)
233
- : 0;
234
-
235
- const hasCriticalBlocker = !evidence.noCriticalBugs;
236
- const verdict = determineVerdict(score, 95, hasCriticalBlocker);
237
-
238
- return { score, criteriaResults, allCriteria, warnings, verdict };
239
- }
240
- }
@@ -1,181 +0,0 @@
1
- /**
2
- * @fileoverview G5 — Deploy Ready Gate
3
- *
4
- * Pre-Deploy gate that validates everything is ready for deployment.
5
- * Checks that QA-Implementation passed, documentation is updated,
6
- * release notes exist, all tasks are complete, and no blockers remain.
7
- */
8
-
9
- import { existsSync } from 'node:fs';
10
- import { join } from 'node:path';
11
- import { GateBase } from './gate-base.js';
12
- import { loadSession } from '../orchestrator/session-manager.js';
13
- import { loadHandoff } from '../tasks/handoff.js';
14
- import { resolveFrameworkDir } from '../utils/framework-dir.js';
15
-
16
- export class DeployReadyGate extends GateBase {
17
- constructor() {
18
- super({
19
- id: 'g5-deploy-ready',
20
- name: 'Deploy Ready',
21
- pipelinePoint: 'pre-deploy',
22
- agent: 'devops',
23
- });
24
- }
25
-
26
- /**
27
- * Collect evidence about deployment readiness.
28
- *
29
- * @param {string} projectDir
30
- * @returns {object} Evidence about QA status, docs, release notes, blockers
31
- */
32
- _collectEvidence(projectDir) {
33
- const evidence = {
34
- qaImplPassed: false,
35
- readmeUpdated: false,
36
- changelogUpdated: false,
37
- releaseNotesPrepared: false,
38
- allTasksCompleted: false,
39
- noOpenBlockers: true,
40
- sessionState: null,
41
- };
42
-
43
- // Check QA-Implementation status
44
- const qaHandoff = loadHandoff(projectDir, 'qa-implementation');
45
- if (qaHandoff.loaded && qaHandoff.handoff) {
46
- evidence.qaImplPassed = qaHandoff.handoff.score >= 90 &&
47
- qaHandoff.handoff.status === 'complete';
48
- }
49
-
50
- // Check README exists
51
- const readmePaths = [
52
- join(projectDir, 'README.md'),
53
- join(projectDir, 'readme.md'),
54
- ];
55
- for (const readmePath of readmePaths) {
56
- if (existsSync(readmePath)) {
57
- evidence.readmeUpdated = true;
58
- break;
59
- }
60
- }
61
-
62
- // Check CHANGELOG exists
63
- const changelogPaths = [
64
- join(projectDir, 'CHANGELOG.md'),
65
- join(projectDir, 'docs', 'CHANGELOG.md'),
66
- join(projectDir, 'changelog.md'),
67
- join(projectDir, 'CHANGES.md'),
68
- ];
69
- for (const clPath of changelogPaths) {
70
- if (existsSync(clPath)) {
71
- evidence.changelogUpdated = true;
72
- break;
73
- }
74
- }
75
-
76
- // Check release notes
77
- const releaseNotePaths = [
78
- join(projectDir, 'RELEASE.md'),
79
- join(projectDir, resolveFrameworkDir(projectDir), 'artifacts', 'release-notes.md'),
80
- ];
81
- for (const rnPath of releaseNotePaths) {
82
- if (existsSync(rnPath)) {
83
- evidence.releaseNotesPrepared = true;
84
- break;
85
- }
86
- }
87
-
88
- // Load session state
89
- const sessionResult = loadSession(projectDir);
90
- if (sessionResult.loaded && sessionResult.session) {
91
- const agents = sessionResult.session.agents || {};
92
- const completedAgents = sessionResult.session.completed_agents || [];
93
-
94
- // Check all required agents are completed
95
- const requiredAgents = Object.keys(agents).filter(
96
- a => agents[a].status !== 'skipped'
97
- );
98
- const allComplete = requiredAgents.every(
99
- a => completedAgents.includes(a) || agents[a].status === 'completed'
100
- );
101
-
102
- evidence.allTasksCompleted = allComplete;
103
-
104
- // Check for open blockers in any handoff
105
- for (const agentName of completedAgents) {
106
- const agentHandoff = loadHandoff(projectDir, agentName);
107
- if (agentHandoff.loaded && agentHandoff.handoff) {
108
- const blockers = agentHandoff.handoff.blockers || [];
109
- if (blockers.length > 0) {
110
- evidence.noOpenBlockers = false;
111
- break;
112
- }
113
- }
114
- }
115
-
116
- evidence.sessionState = {
117
- mode: sessionResult.session.mode,
118
- completedCount: completedAgents.length,
119
- totalAgents: Object.keys(agents).length,
120
- };
121
- }
122
-
123
- return evidence;
124
- }
125
-
126
- /**
127
- * Validate deployment readiness evidence.
128
- *
129
- * @param {object} evidence
130
- * @returns {{ score: number, criteriaResults: string[], allCriteria: string[], warnings: string[] }}
131
- */
132
- _validateEvidence(evidence) {
133
- const allCriteria = [
134
- 'QA-Implementation passed',
135
- 'README updated',
136
- 'CHANGELOG updated',
137
- 'Release notes prepared',
138
- 'All tasks completed',
139
- 'No open blockers',
140
- ];
141
-
142
- const criteriaResults = [];
143
- const warnings = [];
144
-
145
- if (evidence.qaImplPassed) {
146
- criteriaResults.push('QA-Implementation passed');
147
- } else {
148
- warnings.push('QA-Implementation has not passed');
149
- }
150
-
151
- if (evidence.readmeUpdated) {
152
- criteriaResults.push('README updated');
153
- }
154
-
155
- if (evidence.changelogUpdated) {
156
- criteriaResults.push('CHANGELOG updated');
157
- }
158
-
159
- if (evidence.releaseNotesPrepared) {
160
- criteriaResults.push('Release notes prepared');
161
- }
162
-
163
- if (evidence.allTasksCompleted) {
164
- criteriaResults.push('All tasks completed');
165
- } else {
166
- warnings.push('Not all tasks are completed');
167
- }
168
-
169
- if (evidence.noOpenBlockers) {
170
- criteriaResults.push('No open blockers');
171
- } else {
172
- warnings.push('Open blockers remain from agent handoffs');
173
- }
174
-
175
- const score = allCriteria.length > 0
176
- ? Math.round((criteriaResults.length / allCriteria.length) * 100)
177
- : 0;
178
-
179
- return { score, criteriaResults, allCriteria, warnings };
180
- }
181
- }
@@ -1,185 +0,0 @@
1
- /**
2
- * @fileoverview GateBase — Template Method pattern base class for quality gates.
3
- *
4
- * Provides the abstract skeleton for all pipeline quality gates.
5
- * Subclasses implement _collectEvidence() and _validateEvidence()
6
- * while this base class handles evaluation orchestration.
7
- */
8
-
9
- import { evaluateGate, getGateThreshold, resolveGateAction } from '../autonomy/autonomous-gate.js';
10
- import { track as telemetryTrack } from '../telemetry/collector.js';
11
-
12
- /**
13
- * Gate verdict constants (v3.0.0).
14
- * APPROVED: Score >= threshold — proceed to next pipeline stage.
15
- * NEEDS_REVISION: Score within 5 points below threshold — return to agent for fixes.
16
- * BLOCKED: Score significantly below threshold or critical blocker — halt pipeline.
17
- */
18
- export const GateVerdict = {
19
- APPROVED: 'approved',
20
- NEEDS_REVISION: 'needs_revision',
21
- BLOCKED: 'blocked',
22
- };
23
-
24
- /**
25
- * Determine the gate verdict from a score and threshold.
26
- *
27
- * @param {number} score - Gate evaluation score (0-100)
28
- * @param {number} threshold - Minimum score to pass
29
- * @param {boolean} [hasCriticalBlocker=false] - Whether a critical blocker exists
30
- * @returns {string} One of GateVerdict values
31
- */
32
- export function determineVerdict(score, threshold, hasCriticalBlocker = false) {
33
- if (hasCriticalBlocker) return GateVerdict.BLOCKED;
34
- if (score >= threshold) return GateVerdict.APPROVED;
35
- if (score >= threshold - 5) return GateVerdict.NEEDS_REVISION;
36
- return GateVerdict.BLOCKED;
37
- }
38
-
39
- /**
40
- * Abstract base class for quality gates.
41
- *
42
- * Uses the Template Method pattern: evaluate() is the template that
43
- * calls _collectEvidence() and _validateEvidence() which subclasses implement.
44
- */
45
- export class GateBase {
46
- /**
47
- * @param {object} config
48
- * @param {string} config.id - Unique gate identifier (e.g. 'g1-planning-complete')
49
- * @param {string} config.name - Human-readable gate name
50
- * @param {string} config.pipelinePoint - Pipeline point this gate guards
51
- * @param {string} config.agent - Agent whose output this gate evaluates
52
- */
53
- constructor(config) {
54
- if (new.target === GateBase) {
55
- throw new Error('GateBase is abstract and cannot be instantiated directly.');
56
- }
57
-
58
- const { id, name, pipelinePoint, agent } = config;
59
-
60
- if (!id || !name || !pipelinePoint || !agent) {
61
- throw new Error('GateBase requires id, name, pipelinePoint, and agent in config.');
62
- }
63
-
64
- this.id = id;
65
- this.name = name;
66
- this.pipelinePoint = pipelinePoint;
67
- this.agent = agent;
68
- }
69
-
70
- /**
71
- * Evaluate the quality gate.
72
- *
73
- * Template Method: collects evidence, validates it, then either runs
74
- * autonomous evaluation or returns recommendation for human review.
75
- *
76
- * @param {string} projectDir - Project root directory
77
- * @param {string} [mode='autonomous'] - 'autonomous' or 'human-in-the-loop'
78
- * @returns {object} GateResult: { result, score, evidence, recommendation, canProceed }
79
- */
80
- evaluate(projectDir, mode = 'autonomous') {
81
- // Step 1: Collect evidence (subclass implements)
82
- const evidence = this._collectEvidence(projectDir);
83
-
84
- // Step 2: Validate evidence (subclass implements)
85
- const validation = this._validateEvidence(evidence);
86
-
87
- const { score, criteriaResults, allCriteria, warnings = [] } = validation;
88
-
89
- if (mode === 'autonomous') {
90
- // Step 3a: Autonomous evaluation via autonomous-gate module
91
- const gateResult = evaluateGate({
92
- agent: this.agent,
93
- score,
94
- criteriaResults,
95
- allCriteria,
96
- warnings,
97
- });
98
-
99
- const action = resolveGateAction(gateResult.result, mode);
100
-
101
- const threshold = getGateThreshold(this.agent);
102
- const hasCriticalBlocker = warnings.some(w => w.toLowerCase().includes('critical'));
103
- const verdict = determineVerdict(gateResult.score, threshold, hasCriticalBlocker);
104
-
105
- // Track telemetry
106
- telemetryTrack('gate_evaluated', {
107
- gate: this.id,
108
- result: verdict,
109
- score: gateResult.score,
110
- blockers: warnings.filter(w => w.toLowerCase().includes('critical')),
111
- });
112
-
113
- return {
114
- gateId: this.id,
115
- gateName: this.name,
116
- result: gateResult.result,
117
- verdict,
118
- score: gateResult.score,
119
- evidence,
120
- recommendation: action.action,
121
- canProceed: verdict === GateVerdict.APPROVED,
122
- details: gateResult.details,
123
- warnings,
124
- };
125
- }
126
-
127
- // Step 3b: Human-in-the-loop — return evidence + recommendation
128
- const threshold = getGateThreshold(this.agent);
129
- const recommendation = score >= threshold
130
- ? 'Recommend approval — criteria met.'
131
- : `Recommend review — score ${score} below threshold ${threshold}.`;
132
-
133
- return {
134
- gateId: this.id,
135
- gateName: this.name,
136
- result: 'review',
137
- score,
138
- evidence,
139
- recommendation,
140
- canProceed: false, // Human must explicitly approve
141
- details: {
142
- criteriaResults,
143
- allCriteria,
144
- threshold,
145
- },
146
- warnings,
147
- };
148
- }
149
-
150
- /**
151
- * Collect evidence from the project filesystem.
152
- * ABSTRACT — subclass MUST implement.
153
- *
154
- * @param {string} _projectDir
155
- * @returns {object} Evidence data
156
- */
157
- _collectEvidence(_projectDir) {
158
- throw new Error(`${this.constructor.name} must implement _collectEvidence()`);
159
- }
160
-
161
- /**
162
- * Validate collected evidence and produce a score.
163
- * ABSTRACT — subclass MUST implement.
164
- *
165
- * @param {object} _evidence
166
- * @returns {{ score: number, criteriaResults: string[], allCriteria: string[], warnings: string[] }}
167
- */
168
- _validateEvidence(_evidence) {
169
- throw new Error(`${this.constructor.name} must implement _validateEvidence()`);
170
- }
171
-
172
- /**
173
- * Get gate metadata.
174
- *
175
- * @returns {{ id: string, name: string, pipelinePoint: string, threshold: number }}
176
- */
177
- getInfo() {
178
- return {
179
- id: this.id,
180
- name: this.name,
181
- pipelinePoint: this.pipelinePoint,
182
- threshold: getGateThreshold(this.agent),
183
- };
184
- }
185
- }
@@ -1,46 +0,0 @@
1
- /**
2
- * @fileoverview Quality Gates barrel exports and registry.
3
- *
4
- * Provides all gate classes and a registry function to look up
5
- * the appropriate gate for a given pipeline point.
6
- */
7
-
8
- export { GateBase } from './gate-base.js';
9
- export { CircuitBreaker, CIRCUIT_STATES } from './circuit-breaker.js';
10
- export { PlanningCompleteGate } from './g1-planning-complete.js';
11
- export { QAPlanningGate } from './g2-qa-planning.js';
12
- export { ImplementationGate } from './g3-implementation.js';
13
- export { QAImplementationGate, QA_IMPL_VERDICTS } from './g4-qa-implementation.js';
14
- export { DeployReadyGate } from './g5-deploy-ready.js';
15
-
16
- import { PlanningCompleteGate as _G1 } from './g1-planning-complete.js';
17
- import { QAPlanningGate as _G2 } from './g2-qa-planning.js';
18
- import { ImplementationGate as _G3 } from './g3-implementation.js';
19
- import { QAImplementationGate as _G4 } from './g4-qa-implementation.js';
20
- import { DeployReadyGate as _G5 } from './g5-deploy-ready.js';
21
-
22
- /**
23
- * Pipeline point to gate class mapping.
24
- */
25
- const PIPELINE_POINT_MAP = {
26
- 'pre-build': _G1,
27
- 'post-qa-planning': _G2,
28
- 'post-dev': _G3,
29
- 'post-qa-impl': _G4,
30
- 'pre-deploy': _G5,
31
- };
32
-
33
- /**
34
- * Get the gate instance for a specific pipeline point.
35
- *
36
- * @param {string} point - Pipeline point identifier
37
- * @returns {import('./gate-base.js').GateBase} Gate instance
38
- * @throws {Error} If no gate is registered for the given point
39
- */
40
- export function getGateForPipelinePoint(point) {
41
- const GateClass = PIPELINE_POINT_MAP[point];
42
- if (!GateClass) {
43
- throw new Error(`No gate registered for pipeline point: ${point}`);
44
- }
45
- return new GateClass();
46
- }