@howlil/ez-agents 3.4.2 → 4.0.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.
- package/README.md +735 -462
- package/agents/ez-architect-agent.md +267 -0
- package/agents/ez-backend-agent.md +303 -0
- package/agents/ez-chief-strategist.md +271 -0
- package/agents/ez-codebase-mapper.md +770 -770
- package/agents/ez-context-manager.md +319 -0
- package/agents/ez-debugger.md +1255 -1255
- package/agents/ez-design-expert.md +347 -0
- package/agents/ez-devops-agent.md +331 -0
- package/agents/ez-executor.md +487 -487
- package/agents/ez-frontend-agent.md +322 -0
- package/agents/ez-phase-researcher.md +553 -553
- package/agents/ez-planner.md +1307 -1307
- package/agents/ez-product-engineer.md +435 -0
- package/agents/ez-project-researcher.md +629 -629
- package/agents/ez-qa-agent.md +320 -0
- package/agents/ez-release-agent.md +333 -0
- package/agents/ez-requirements-agent.md +377 -0
- package/agents/ez-roadmapper.md +650 -650
- package/agents/ez-technical-writer.md +551 -0
- package/agents/ez-ux-expert.md +393 -0
- package/agents/ez-verifier.md +579 -579
- package/bin/guards/autonomy-guard.cjs +346 -0
- package/bin/guards/context-budget-guard.cjs +278 -0
- package/bin/guards/hallucination-guard.cjs +380 -0
- package/bin/guards/hidden-state-guard.cjs +182 -0
- package/bin/guards/team-overhead-guard.cjs +266 -0
- package/bin/guards/tool-sprawl-guard.cjs +271 -0
- package/bin/install.js +3221 -3272
- package/bin/lib/analytics/analytics-collector.cjs +86 -0
- package/bin/lib/analytics/analytics-reporter.cjs +130 -0
- package/bin/lib/analytics/cohort-analyzer.cjs +138 -0
- package/bin/lib/analytics/funnel-analyzer.cjs +147 -0
- package/bin/lib/analytics/nps-tracker.cjs +147 -0
- package/bin/lib/archetype-detector.cjs +289 -0
- package/bin/lib/assistant-adapter.cjs +361 -0
- package/bin/lib/audit-exec.cjs +175 -0
- package/bin/lib/auth.cjs +176 -0
- package/bin/lib/backup-service.cjs +422 -0
- package/bin/lib/bdd-validator.cjs +622 -0
- package/bin/lib/business-flow-mapper.cjs +429 -0
- package/bin/lib/circuit-breaker.cjs +276 -0
- package/bin/lib/code-complexity-analyzer.cjs +360 -0
- package/bin/lib/codebase-analyzer.cjs +241 -0
- package/bin/lib/commands.cjs +691 -0
- package/bin/lib/config.cjs +236 -0
- package/bin/lib/constraint-extractor.cjs +526 -0
- package/bin/lib/content-scanner.cjs +238 -0
- package/bin/lib/context-cache.cjs +154 -0
- package/bin/lib/context-compressor.cjs +102 -0
- package/bin/lib/context-deduplicator.cjs +105 -0
- package/bin/lib/context-errors.cjs +78 -0
- package/bin/lib/context-manager.cjs +338 -0
- package/bin/lib/context-metadata-tracker.cjs +140 -0
- package/bin/lib/context-relevance-scorer.cjs +99 -0
- package/bin/lib/core.cjs +507 -0
- package/bin/lib/cost-alerts.cjs +174 -0
- package/bin/lib/cost-tracker.cjs +275 -0
- package/bin/lib/crash-recovery.cjs +220 -0
- package/bin/lib/dependency-graph.cjs +319 -0
- package/bin/lib/deploy/deploy-audit-log.cjs +76 -0
- package/bin/lib/deploy/deploy-detector.cjs +69 -0
- package/bin/lib/deploy/deploy-env-manager.cjs +109 -0
- package/bin/lib/deploy/deploy-health-check.cjs +88 -0
- package/bin/lib/deploy/deploy-pre-flight.cjs +57 -0
- package/bin/lib/deploy/deploy-rollback.cjs +72 -0
- package/bin/lib/deploy/deploy-runner.cjs +97 -0
- package/bin/lib/deploy/deploy-status.cjs +74 -0
- package/bin/lib/discussion-synthesizer.cjs +439 -0
- package/bin/lib/error-cache.cjs +114 -0
- package/bin/lib/error-registry.cjs +177 -0
- package/bin/lib/file-access.cjs +207 -0
- package/bin/lib/file-lock.cjs +236 -0
- package/bin/lib/finops/budget-enforcer.cjs +126 -0
- package/bin/lib/finops/cost-reporter.cjs +132 -0
- package/bin/lib/finops/finops-analyzer.cjs +112 -0
- package/bin/lib/finops/spot-manager.cjs +118 -0
- package/bin/lib/framework-detector.cjs +396 -0
- package/bin/lib/frontmatter.cjs +313 -0
- package/bin/lib/fs-utils.cjs +153 -0
- package/bin/lib/gate-executor.cjs +272 -0
- package/bin/lib/gates/README.md +374 -0
- package/bin/lib/gates/gate-01-requirement.cjs +303 -0
- package/bin/lib/gates/gate-02-architecture.cjs +555 -0
- package/bin/lib/gates/gate-03-code.cjs +635 -0
- package/bin/lib/gates/gate-04-security.cjs +829 -0
- package/bin/lib/git-errors.cjs +83 -0
- package/bin/lib/git-utils.cjs +321 -0
- package/bin/lib/git-workflow-engine.cjs +1157 -0
- package/bin/lib/health-check.cjs +227 -0
- package/bin/lib/index.cjs +279 -0
- package/bin/lib/init.cjs +725 -0
- package/bin/lib/lock-logger.cjs +194 -0
- package/bin/lib/lock-state.cjs +263 -0
- package/bin/lib/lockfile-validator.cjs +227 -0
- package/bin/lib/log-rotation.cjs +71 -0
- package/bin/lib/logger.cjs +125 -0
- package/bin/lib/memory-compression.cjs +256 -0
- package/bin/lib/milestone.cjs +247 -0
- package/bin/lib/model-provider.cjs +241 -0
- package/bin/lib/package-manager-detector.cjs +203 -0
- package/bin/lib/package-manager-executor.cjs +385 -0
- package/bin/lib/package-manager-service.cjs +216 -0
- package/bin/lib/perf/api-monitor.cjs +88 -0
- package/bin/lib/perf/db-optimizer.cjs +78 -0
- package/bin/lib/perf/frontend-performance.cjs +56 -0
- package/bin/lib/perf/perf-analyzer.cjs +77 -0
- package/bin/lib/perf/perf-baseline.cjs +102 -0
- package/bin/lib/perf/perf-reporter.cjs +117 -0
- package/bin/lib/perf/regression-detector.cjs +92 -0
- package/bin/lib/phase.cjs +963 -0
- package/bin/lib/planning-write.cjs +123 -0
- package/bin/lib/project-reporter.cjs +565 -0
- package/bin/lib/quality-gate.cjs +332 -0
- package/bin/lib/quality-metrics.cjs +324 -0
- package/bin/lib/recovery-manager.cjs +98 -0
- package/bin/lib/release-validator.cjs +617 -0
- package/bin/lib/retry.cjs +119 -0
- package/bin/lib/roadmap.cjs +309 -0
- package/bin/lib/safe-exec.cjs +173 -0
- package/bin/lib/safe-path.cjs +130 -0
- package/bin/lib/security-errors.cjs +62 -0
- package/bin/lib/session-chain.cjs +304 -0
- package/bin/lib/session-errors.cjs +81 -0
- package/bin/lib/session-export.cjs +251 -0
- package/bin/lib/session-import.cjs +262 -0
- package/bin/lib/session-manager.cjs +280 -0
- package/bin/lib/skill-context.cjs +148 -0
- package/bin/lib/skill-matcher.cjs +236 -0
- package/bin/lib/skill-registry.cjs +360 -0
- package/bin/lib/skill-resolver.cjs +449 -0
- package/bin/lib/skill-triggers.cjs +90 -0
- package/bin/lib/skill-validator.cjs +270 -0
- package/bin/lib/skill-versioning.cjs +355 -0
- package/bin/lib/stack-detector.cjs +399 -0
- package/bin/lib/state.cjs +736 -0
- package/bin/lib/tech-debt-analyzer.cjs +309 -0
- package/bin/lib/temp-file.cjs +239 -0
- package/bin/lib/template.cjs +223 -0
- package/bin/lib/test-file-lock.cjs +112 -0
- package/bin/lib/test-graceful.cjs +93 -0
- package/bin/lib/test-logger.cjs +60 -0
- package/bin/lib/test-safe-exec.cjs +38 -0
- package/bin/lib/test-safe-path.cjs +33 -0
- package/bin/lib/test-temp-file.cjs +125 -0
- package/bin/lib/tier-manager.cjs +428 -0
- package/bin/lib/timeout-exec.cjs +63 -0
- package/bin/lib/tradeoff-analyzer.cjs +284 -0
- package/bin/lib/url-fetch.cjs +170 -0
- package/bin/lib/verify.cjs +863 -0
- package/bin/update.js +217 -214
- package/commands/deploy.cjs +53 -0
- package/commands/ez/add-tests.md +41 -41
- package/commands/ez/audit-milestone.md +36 -36
- package/commands/ez/complete-milestone.md +136 -136
- package/commands/ez/discuss-phase.md +90 -90
- package/commands/ez/execute-phase.md +52 -41
- package/commands/ez/help.md +22 -22
- package/commands/ez/map-codebase.md +71 -71
- package/commands/ez/new-milestone.md +44 -44
- package/commands/ez/new-project.md +51 -42
- package/commands/ez/plan-phase.md +53 -45
- package/commands/ez/progress.md +36 -24
- package/commands/ez/quick.md +45 -45
- package/commands/ez/resume-work.md +40 -40
- package/commands/ez/run-phase.md +580 -0
- package/commands/ez/settings.md +36 -36
- package/commands/ez/update.md +37 -37
- package/commands/ez/verify-work.md +402 -38
- package/commands/health-check.cjs +44 -0
- package/commands/rollback.cjs +47 -0
- package/ez-agents/bin/ez-tools.cjs +1692 -716
- package/ez-agents/bin/guards/autonomy-guard.cjs +346 -0
- package/ez-agents/bin/guards/context-budget-guard.cjs +247 -0
- package/ez-agents/bin/guards/hallucination-guard.cjs +271 -0
- package/ez-agents/bin/guards/hidden-state-guard.cjs +182 -0
- package/ez-agents/bin/guards/team-overhead-guard.cjs +266 -0
- package/ez-agents/bin/guards/tool-sprawl-guard.cjs +271 -0
- package/ez-agents/bin/lib/analytics/analytics-collector.cjs +86 -0
- package/ez-agents/bin/lib/analytics/analytics-reporter.cjs +130 -0
- package/ez-agents/bin/lib/analytics/cohort-analyzer.cjs +138 -0
- package/ez-agents/bin/lib/analytics/funnel-analyzer.cjs +147 -0
- package/ez-agents/bin/lib/analytics/nps-tracker.cjs +147 -0
- package/ez-agents/bin/lib/archetype-detector.cjs +289 -0
- package/ez-agents/bin/lib/audit-exec.cjs +166 -167
- package/ez-agents/bin/lib/auth.cjs +176 -176
- package/ez-agents/bin/lib/backup-service.cjs +422 -0
- package/ez-agents/bin/lib/bdd-validator.cjs +622 -0
- package/ez-agents/bin/lib/business-flow-mapper.cjs +429 -0
- package/ez-agents/bin/lib/code-complexity-analyzer.cjs +360 -0
- package/ez-agents/bin/lib/codebase-analyzer.cjs +241 -0
- package/ez-agents/bin/lib/commands.cjs +685 -685
- package/ez-agents/bin/lib/config.cjs +41 -1
- package/ez-agents/bin/lib/constraint-extractor.cjs +526 -0
- package/ez-agents/bin/lib/content-scanner.cjs +238 -0
- package/ez-agents/bin/lib/context-cache.cjs +154 -0
- package/ez-agents/bin/lib/context-errors.cjs +71 -0
- package/ez-agents/bin/lib/context-manager.cjs +220 -0
- package/ez-agents/bin/lib/core.cjs +507 -512
- package/ez-agents/bin/lib/cost-tracker.cjs +243 -0
- package/ez-agents/bin/lib/crash-recovery.cjs +172 -0
- package/ez-agents/bin/lib/dependency-graph.cjs +319 -0
- package/ez-agents/bin/lib/deploy/deploy-audit-log.cjs +76 -0
- package/ez-agents/bin/lib/deploy/deploy-detector.cjs +69 -0
- package/ez-agents/bin/lib/deploy/deploy-env-manager.cjs +109 -0
- package/ez-agents/bin/lib/deploy/deploy-health-check.cjs +88 -0
- package/ez-agents/bin/lib/deploy/deploy-pre-flight.cjs +57 -0
- package/ez-agents/bin/lib/deploy/deploy-rollback.cjs +72 -0
- package/ez-agents/bin/lib/deploy/deploy-runner.cjs +97 -0
- package/ez-agents/bin/lib/deploy/deploy-status.cjs +74 -0
- package/ez-agents/bin/lib/discussion-synthesizer.cjs +458 -0
- package/ez-agents/bin/lib/file-access.cjs +207 -0
- package/ez-agents/bin/lib/finops/budget-enforcer.cjs +126 -0
- package/ez-agents/bin/lib/finops/cost-reporter.cjs +132 -0
- package/ez-agents/bin/lib/finops/finops-analyzer.cjs +112 -0
- package/ez-agents/bin/lib/finops/spot-manager.cjs +118 -0
- package/ez-agents/bin/lib/framework-detector.cjs +396 -0
- package/ez-agents/bin/lib/frontmatter.cjs +3 -1
- package/ez-agents/bin/lib/gates/README.md +374 -0
- package/ez-agents/bin/lib/gates/gate-01-requirement.cjs +303 -0
- package/ez-agents/bin/lib/gates/gate-02-architecture.cjs +555 -0
- package/ez-agents/bin/lib/gates/gate-03-code.cjs +635 -0
- package/ez-agents/bin/lib/gates/gate-04-security.cjs +829 -0
- package/ez-agents/bin/lib/git-errors.cjs +83 -0
- package/ez-agents/bin/lib/git-utils.cjs +118 -0
- package/ez-agents/bin/lib/git-workflow-engine.cjs +1157 -0
- package/ez-agents/bin/lib/health-check.cjs +162 -162
- package/ez-agents/bin/lib/index.cjs +40 -2
- package/ez-agents/bin/lib/init.cjs +0 -2
- package/ez-agents/bin/lib/lockfile-validator.cjs +227 -0
- package/ez-agents/bin/lib/log-rotation.cjs +71 -0
- package/ez-agents/bin/lib/logger.cjs +99 -154
- package/ez-agents/bin/lib/memory-compression.cjs +256 -0
- package/ez-agents/bin/lib/package-manager-detector.cjs +203 -0
- package/ez-agents/bin/lib/package-manager-executor.cjs +385 -0
- package/ez-agents/bin/lib/package-manager-service.cjs +216 -0
- package/ez-agents/bin/lib/perf/api-monitor.cjs +88 -0
- package/ez-agents/bin/lib/perf/db-optimizer.cjs +78 -0
- package/ez-agents/bin/lib/perf/frontend-performance.cjs +56 -0
- package/ez-agents/bin/lib/perf/perf-analyzer.cjs +77 -0
- package/ez-agents/bin/lib/perf/perf-baseline.cjs +102 -0
- package/ez-agents/bin/lib/perf/perf-reporter.cjs +117 -0
- package/ez-agents/bin/lib/perf/regression-detector.cjs +92 -0
- package/ez-agents/bin/lib/project-reporter.cjs +502 -0
- package/ez-agents/bin/lib/quality-gate.cjs +332 -0
- package/ez-agents/bin/lib/recovery-manager.cjs +98 -0
- package/ez-agents/bin/lib/release-validator.cjs +617 -0
- package/ez-agents/bin/lib/safe-exec.cjs +128 -214
- package/ez-agents/bin/lib/security-errors.cjs +62 -0
- package/ez-agents/bin/lib/session-chain.cjs +304 -0
- package/ez-agents/bin/lib/session-errors.cjs +81 -0
- package/ez-agents/bin/lib/session-export.cjs +251 -0
- package/ez-agents/bin/lib/session-import.cjs +262 -0
- package/ez-agents/bin/lib/session-manager.cjs +280 -0
- package/ez-agents/bin/lib/skill-context.cjs +148 -0
- package/ez-agents/bin/lib/skill-matcher.cjs +236 -0
- package/ez-agents/bin/lib/skill-registry.cjs +341 -0
- package/ez-agents/bin/lib/skill-resolver.cjs +449 -0
- package/ez-agents/bin/lib/skill-triggers.cjs +90 -0
- package/ez-agents/bin/lib/skill-validator.cjs +270 -0
- package/ez-agents/bin/lib/skill-versioning.cjs +355 -0
- package/ez-agents/bin/lib/stack-detector.cjs +399 -0
- package/ez-agents/bin/lib/tech-debt-analyzer.cjs +309 -0
- package/ez-agents/bin/lib/tier-manager.cjs +428 -0
- package/ez-agents/bin/lib/tradeoff-analyzer.cjs +284 -0
- package/ez-agents/bin/lib/url-fetch.cjs +170 -0
- package/ez-agents/bin/lib/verify.cjs +863 -863
- package/ez-agents/references/decimal-phase-calculation.md +65 -65
- package/ez-agents/references/git-integration.md +248 -248
- package/ez-agents/references/git-planning-commit.md +38 -38
- package/ez-agents/references/metrics-schema.md +118 -0
- package/ez-agents/references/model-profile-resolution.md +34 -34
- package/ez-agents/references/model-profiles.md +93 -93
- package/ez-agents/references/phase-argument-parsing.md +61 -61
- package/ez-agents/references/planning-config.md +340 -200
- package/ez-agents/references/tier-strategy.md +103 -0
- package/ez-agents/references/ui-brand.md +160 -160
- package/ez-agents/references/verification-patterns.md +612 -612
- package/ez-agents/templates/DEBUG.md +164 -164
- package/ez-agents/templates/UAT.md +247 -247
- package/ez-agents/templates/agent-output-format.md +404 -0
- package/ez-agents/templates/bdd-feature.md +173 -0
- package/ez-agents/templates/codebase/architecture.md +255 -255
- package/ez-agents/templates/codebase/structure.md +285 -285
- package/ez-agents/templates/copilot-instructions.md +7 -7
- package/ez-agents/templates/debug-subagent-prompt.md +91 -91
- package/ez-agents/templates/discovery.md +146 -146
- package/ez-agents/templates/discussion.md +68 -0
- package/ez-agents/templates/handoff-protocol.md +294 -0
- package/ez-agents/templates/incident-runbook.md +205 -0
- package/ez-agents/templates/mode-workflow-templates.md +301 -0
- package/ez-agents/templates/phase-prompt.md +610 -610
- package/ez-agents/templates/planner-subagent-prompt.md +117 -117
- package/ez-agents/templates/project.md +184 -184
- package/ez-agents/templates/release-checklist.md +136 -0
- package/ez-agents/templates/research.md +552 -552
- package/ez-agents/templates/rollback-plan.md +201 -0
- package/ez-agents/templates/security-user-setup.md +244 -0
- package/ez-agents/templates/skill-validation-rules.md +476 -0
- package/ez-agents/templates/state.md +180 -176
- package/ez-agents/templates/summary-complex.md +59 -59
- package/ez-agents/tests/gates/gate-01-02.test.cjs +812 -0
- package/ez-agents/tests/gates/gate-03-04.test.cjs +762 -0
- package/ez-agents/tests/gates/gate-05-validator.test.cjs +145 -0
- package/ez-agents/tests/gates/gate-06-docs-validator.test.cjs +244 -0
- package/ez-agents/tests/gates/gate-07-release-validator.test.cjs +219 -0
- package/ez-agents/tests/guards/context-budget-guard.test.cjs +145 -0
- package/ez-agents/tests/guards/edge-case-guards.test.cjs +238 -0
- package/ez-agents/tests/guards/hallucination-guard.test.cjs +124 -0
- package/ez-agents/workflows/audit-milestone.md +1 -1
- package/ez-agents/workflows/autonomous.md +131 -30
- package/ez-agents/workflows/complete-milestone.md +1 -1
- package/ez-agents/workflows/discuss-phase.md +1 -1
- package/ez-agents/workflows/execute-phase.md +169 -3
- package/ez-agents/workflows/help.md +86 -133
- package/ez-agents/workflows/hotfix.md +291 -0
- package/ez-agents/workflows/new-milestone.md +340 -11
- package/ez-agents/workflows/new-project.md +294 -318
- package/ez-agents/workflows/plan-phase.md +22 -40
- package/ez-agents/workflows/progress.md +15 -25
- package/ez-agents/workflows/release.md +253 -0
- package/ez-agents/workflows/resume-session.md +215 -0
- package/ez-agents/workflows/run-phase.md +531 -0
- package/ez-agents/workflows/settings.md +2 -35
- package/hooks/dist/ez-check-update.js +81 -81
- package/hooks/dist/ez-context-monitor.js +148 -141
- package/hooks/dist/ez-statusline.js +115 -115
- package/package.json +78 -64
- package/scripts/fix-qwen-installation.js +144 -144
- package/agents/ez-integration-checker.md +0 -443
- package/agents/ez-nyquist-auditor.md +0 -176
- package/agents/ez-plan-checker.md +0 -706
- package/agents/ez-research-synthesizer.md +0 -247
- package/agents/ez-ui-auditor.md +0 -439
- package/agents/ez-ui-checker.md +0 -300
- package/agents/ez-ui-researcher.md +0 -353
- package/commands/ez/add-phase.md +0 -43
- package/commands/ez/add-todo.md +0 -47
- package/commands/ez/auth.md +0 -87
- package/commands/ez/autonomous.md +0 -41
- package/commands/ez/check-todos.md +0 -45
- package/commands/ez/cleanup.md +0 -18
- package/commands/ez/debug.md +0 -168
- package/commands/ez/health.md +0 -22
- package/commands/ez/insert-phase.md +0 -32
- package/commands/ez/join-discord.md +0 -18
- package/commands/ez/list-phase-assumptions.md +0 -46
- package/commands/ez/pause-work.md +0 -38
- package/commands/ez/plan-milestone-gaps.md +0 -34
- package/commands/ez/reapply-patches.md +0 -124
- package/commands/ez/remove-phase.md +0 -31
- package/commands/ez/research-phase.md +0 -190
- package/commands/ez/set-profile.md +0 -34
- package/commands/ez/stats.md +0 -18
- package/commands/ez/ui-phase.md +0 -34
- package/commands/ez/ui-review.md +0 -32
- package/commands/ez/validate-phase.md +0 -35
- package/ez-agents/templates/UI-SPEC.md +0 -100
- package/ez-agents/templates/VALIDATION.md +0 -76
- package/ez-agents/templates/context.md +0 -352
- package/ez-agents/templates/verification-report.md +0 -322
- package/ez-agents/workflows/research-phase.md +0 -74
- package/ez-agents/workflows/ui-phase.md +0 -290
- package/ez-agents/workflows/ui-review.md +0 -157
- package/ez-agents/workflows/validate-phase.md +0 -167
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
# Quality Gate Implementation Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how to implement quality gates using the Quality Gate Coordinator.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Quality Gate Coordinator provides a central registry and execution engine for quality gates. Each gate:
|
|
8
|
+
|
|
9
|
+
1. **Validates input** using Zod schemas
|
|
10
|
+
2. **Executes checks** via a custom executor function
|
|
11
|
+
3. **Returns structured results** with pass/fail status, errors, and warnings
|
|
12
|
+
4. **Supports bypass** with mandatory audit trail
|
|
13
|
+
|
|
14
|
+
## API Reference
|
|
15
|
+
|
|
16
|
+
### `registerGate(id, schema, executor)`
|
|
17
|
+
|
|
18
|
+
Registers a new quality gate.
|
|
19
|
+
|
|
20
|
+
**Parameters:**
|
|
21
|
+
- `id` (string): Unique gate identifier (e.g., `"requirement-completeness"`)
|
|
22
|
+
- `schema` (ZodSchema): Zod schema for validating gate context
|
|
23
|
+
- `executor` (Function): Async function that executes the gate logic
|
|
24
|
+
|
|
25
|
+
**Example:**
|
|
26
|
+
```javascript
|
|
27
|
+
const { QualityGate, z } = require('./quality-gate.cjs');
|
|
28
|
+
|
|
29
|
+
const gates = new QualityGate();
|
|
30
|
+
|
|
31
|
+
gates.registerGate(
|
|
32
|
+
'requirement-completeness',
|
|
33
|
+
z.object({
|
|
34
|
+
requirements: z.array(z.object({
|
|
35
|
+
id: z.string(),
|
|
36
|
+
description: z.string(),
|
|
37
|
+
acceptanceCriteria: z.array(z.string()),
|
|
38
|
+
})),
|
|
39
|
+
}),
|
|
40
|
+
async (context) => {
|
|
41
|
+
const errors = [];
|
|
42
|
+
const warnings = [];
|
|
43
|
+
|
|
44
|
+
for (const req of context.requirements) {
|
|
45
|
+
if (!req.id || req.id.length === 0) {
|
|
46
|
+
errors.push({ path: 'requirements[].id', message: 'Requirement ID is required' });
|
|
47
|
+
}
|
|
48
|
+
if (req.acceptanceCriteria.length === 0) {
|
|
49
|
+
warnings.push(`Requirement ${req.id} has no acceptance criteria`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
passed: errors.length === 0,
|
|
55
|
+
errors,
|
|
56
|
+
warnings,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### `executeGate(id, context)`
|
|
63
|
+
|
|
64
|
+
Executes a registered gate with the provided context.
|
|
65
|
+
|
|
66
|
+
**Parameters:**
|
|
67
|
+
- `id` (string): Gate identifier
|
|
68
|
+
- `context` (any): Context data to validate and pass to executor
|
|
69
|
+
|
|
70
|
+
**Returns:** `Promise<ExecutionResult>`
|
|
71
|
+
```javascript
|
|
72
|
+
{
|
|
73
|
+
passed: boolean,
|
|
74
|
+
errors: Array<{ path: string, message: string }>,
|
|
75
|
+
warnings: Array<string>,
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Example:**
|
|
80
|
+
```javascript
|
|
81
|
+
const result = await gates.executeGate('requirement-completeness', {
|
|
82
|
+
requirements: [
|
|
83
|
+
{
|
|
84
|
+
id: 'REQ-001',
|
|
85
|
+
description: 'User can log in',
|
|
86
|
+
acceptanceCriteria: ['Given valid credentials', 'When login form submitted', 'Then user is authenticated'],
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
if (result.passed) {
|
|
92
|
+
console.log('Gate passed!');
|
|
93
|
+
} else {
|
|
94
|
+
console.error('Gate failed:', result.errors);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### `bypassGate(id, reason)`
|
|
99
|
+
|
|
100
|
+
Bypasses a gate with a mandatory audit reason.
|
|
101
|
+
|
|
102
|
+
**Parameters:**
|
|
103
|
+
- `id` (string): Gate identifier
|
|
104
|
+
- `reason` (string): Non-empty reason for bypass (logged to audit trail)
|
|
105
|
+
|
|
106
|
+
**Example:**
|
|
107
|
+
```javascript
|
|
108
|
+
// Bypass with explicit reason (required)
|
|
109
|
+
gates.bypassGate('security-baseline', 'MVP tier - security audit deferred to Phase 40');
|
|
110
|
+
|
|
111
|
+
// This will throw an error (empty reason not allowed)
|
|
112
|
+
gates.bypassGate('security-baseline', ''); // Error!
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### `getGateStatus(id)`
|
|
116
|
+
|
|
117
|
+
Returns the current status of a gate.
|
|
118
|
+
|
|
119
|
+
**Parameters:**
|
|
120
|
+
- `id` (string): Gate identifier
|
|
121
|
+
|
|
122
|
+
**Returns:** `GateStatus`
|
|
123
|
+
```javascript
|
|
124
|
+
{
|
|
125
|
+
state: 'registered' | 'passed' | 'failed' | 'bypassed',
|
|
126
|
+
id: string,
|
|
127
|
+
registeredAt?: Date,
|
|
128
|
+
executedAt?: Date,
|
|
129
|
+
bypassedAt?: Date,
|
|
130
|
+
bypassReason?: string,
|
|
131
|
+
errors?: Array<{ path: string, message: string }>,
|
|
132
|
+
warnings?: Array<string>,
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Example:**
|
|
137
|
+
```javascript
|
|
138
|
+
const status = gates.getGateStatus('requirement-completeness');
|
|
139
|
+
console.log(`Gate state: ${status.state}`);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Gate Implementation Patterns
|
|
143
|
+
|
|
144
|
+
### Pattern 1: Simple Validation Gate
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
gates.registerGate(
|
|
148
|
+
'plan-completeness',
|
|
149
|
+
z.object({
|
|
150
|
+
tasks: z.array(z.object({
|
|
151
|
+
id: z.string(),
|
|
152
|
+
name: z.string(),
|
|
153
|
+
action: z.string(),
|
|
154
|
+
})),
|
|
155
|
+
}),
|
|
156
|
+
async (context) => {
|
|
157
|
+
const errors = [];
|
|
158
|
+
|
|
159
|
+
if (context.tasks.length === 0) {
|
|
160
|
+
errors.push({ path: 'tasks', message: 'At least one task is required' });
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
passed: errors.length === 0,
|
|
165
|
+
errors,
|
|
166
|
+
warnings: [],
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Pattern 2: Multi-Check Gate
|
|
173
|
+
|
|
174
|
+
```javascript
|
|
175
|
+
gates.registerGate(
|
|
176
|
+
'code-quality',
|
|
177
|
+
z.object({
|
|
178
|
+
files: z.array(z.string()),
|
|
179
|
+
metrics: z.object({
|
|
180
|
+
complexity: z.number(),
|
|
181
|
+
coverage: z.number(),
|
|
182
|
+
}),
|
|
183
|
+
}),
|
|
184
|
+
async (context) => {
|
|
185
|
+
const errors = [];
|
|
186
|
+
const warnings = [];
|
|
187
|
+
|
|
188
|
+
// Check 1: Complexity threshold
|
|
189
|
+
if (context.metrics.complexity > 10) {
|
|
190
|
+
errors.push({ path: 'metrics.complexity', message: 'Cyclomatic complexity exceeds threshold (10)' });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Check 2: Test coverage
|
|
194
|
+
if (context.metrics.coverage < 80) {
|
|
195
|
+
warnings.push(`Test coverage is ${context.metrics.coverage}%, recommended: 80%`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Check 3: File count
|
|
199
|
+
if (context.files.length > 50) {
|
|
200
|
+
warnings.push(`Large change set: ${context.files.length} files modified`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
passed: errors.length === 0,
|
|
205
|
+
errors,
|
|
206
|
+
warnings,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Pattern 3: External Tool Integration Gate
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
const { exec } = require('child_process');
|
|
216
|
+
const { promisify } = require('util');
|
|
217
|
+
const execAsync = promisify(exec);
|
|
218
|
+
|
|
219
|
+
gates.registerGate(
|
|
220
|
+
'security-scan',
|
|
221
|
+
z.object({
|
|
222
|
+
projectPath: z.string(),
|
|
223
|
+
}),
|
|
224
|
+
async (context) => {
|
|
225
|
+
const errors = [];
|
|
226
|
+
const warnings = [];
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
// Run npm audit
|
|
230
|
+
const { stdout } = await execAsync('npm audit --json', {
|
|
231
|
+
cwd: context.projectPath,
|
|
232
|
+
});
|
|
233
|
+
const audit = JSON.parse(stdout);
|
|
234
|
+
|
|
235
|
+
if (audit.metadata.vulnerabilities.critical > 0) {
|
|
236
|
+
errors.push({
|
|
237
|
+
path: 'dependencies',
|
|
238
|
+
message: `Found ${audit.metadata.vulnerabilities.critical} critical vulnerabilities`,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (audit.metadata.vulnerabilities.high > 0) {
|
|
243
|
+
warnings.push(`Found ${audit.metadata.vulnerabilities.high} high severity vulnerabilities`);
|
|
244
|
+
}
|
|
245
|
+
} catch (err) {
|
|
246
|
+
if (err.stdout) {
|
|
247
|
+
const audit = JSON.parse(err.stdout);
|
|
248
|
+
if (audit.metadata.vulnerabilities.total > 0) {
|
|
249
|
+
warnings.push(`npm audit found ${audit.metadata.vulnerabilities.total} vulnerabilities`);
|
|
250
|
+
}
|
|
251
|
+
} else {
|
|
252
|
+
warnings.push('Could not run npm audit');
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
passed: errors.length === 0,
|
|
258
|
+
errors,
|
|
259
|
+
warnings,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Audit Trail
|
|
266
|
+
|
|
267
|
+
All gate bypasses are logged to `.planning/gate-audit.json`:
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
[
|
|
271
|
+
{
|
|
272
|
+
"gateId": "security-baseline",
|
|
273
|
+
"action": "bypass",
|
|
274
|
+
"reason": "MVP tier - security audit deferred to Phase 40",
|
|
275
|
+
"timestamp": "2026-03-21T10:30:00.000Z"
|
|
276
|
+
}
|
|
277
|
+
]
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Error Handling
|
|
281
|
+
|
|
282
|
+
### Schema Validation Errors
|
|
283
|
+
|
|
284
|
+
When context fails schema validation, errors include field paths:
|
|
285
|
+
|
|
286
|
+
```javascript
|
|
287
|
+
const result = await gates.executeGate('requirement-completeness', {
|
|
288
|
+
requirements: [
|
|
289
|
+
{ id: '', description: 'Test' }, // Missing ID
|
|
290
|
+
],
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
// result.errors:
|
|
294
|
+
// [
|
|
295
|
+
// { path: 'requirements.0.id', message: 'Required' },
|
|
296
|
+
// ]
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Executor Errors
|
|
300
|
+
|
|
301
|
+
If the executor throws an exception, it's caught and returned as an error:
|
|
302
|
+
|
|
303
|
+
```javascript
|
|
304
|
+
gates.registerGate(
|
|
305
|
+
'flaky-gate',
|
|
306
|
+
z.object({}),
|
|
307
|
+
async () => {
|
|
308
|
+
throw new Error('Something went wrong');
|
|
309
|
+
}
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
const result = await gates.executeGate('flaky-gate', {});
|
|
313
|
+
// result.passed: false
|
|
314
|
+
// result.errors: [{ path: 'executor', message: 'Something went wrong' }]
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Unregistered Gate
|
|
318
|
+
|
|
319
|
+
Executing an unregistered gate throws an error:
|
|
320
|
+
|
|
321
|
+
```javascript
|
|
322
|
+
await gates.executeGate('nonexistent-gate', {});
|
|
323
|
+
// Throws: Error: Gate not registered: nonexistent-gate
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Best Practices
|
|
327
|
+
|
|
328
|
+
1. **Use descriptive gate IDs**: `requirement-completeness` not `gate1`
|
|
329
|
+
2. **Define strict schemas**: Validate all required fields with Zod
|
|
330
|
+
3. **Return structured errors**: Include field paths for easy debugging
|
|
331
|
+
4. **Use warnings for non-blocking issues**: Distinguish between errors (block) and warnings (inform)
|
|
332
|
+
5. **Document bypass reasons**: Always provide clear, actionable bypass reasons
|
|
333
|
+
6. **Keep executors focused**: Each gate should check one quality dimension
|
|
334
|
+
7. **Test gates independently**: Write unit tests for each gate executor
|
|
335
|
+
|
|
336
|
+
## Integration with Phase Execution
|
|
337
|
+
|
|
338
|
+
```javascript
|
|
339
|
+
const { QualityGate, z } = require('./quality-gate.cjs');
|
|
340
|
+
|
|
341
|
+
async function executePhase(phasePlan) {
|
|
342
|
+
const gates = new QualityGate();
|
|
343
|
+
|
|
344
|
+
// Register gates
|
|
345
|
+
gates.registerGate(/* ... */);
|
|
346
|
+
|
|
347
|
+
// Execute pre-execution gates
|
|
348
|
+
const preCheck = await gates.executeGate('plan-completeness', phasePlan);
|
|
349
|
+
if (!preCheck.passed) {
|
|
350
|
+
throw new Error(`Pre-check failed: ${JSON.stringify(preCheck.errors)}`);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Execute phase tasks...
|
|
354
|
+
|
|
355
|
+
// Execute post-execution gates
|
|
356
|
+
const postCheck = await gates.executeGate('verification-complete', {
|
|
357
|
+
tasks: phasePlan.tasks,
|
|
358
|
+
summaries: taskSummaries,
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
if (!postCheck.passed) {
|
|
362
|
+
// Trigger gap closure workflow
|
|
363
|
+
console.error('Post-check failed:', postCheck.errors);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return postCheck;
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## See Also
|
|
371
|
+
|
|
372
|
+
- Phase 34-03: Gate 1-2 Implementation (Requirement Completeness, Architecture Review)
|
|
373
|
+
- Phase 34-04: Gate 3-4 Implementation (Code Quality, Security Baseline)
|
|
374
|
+
- Phase 40: Gates 5-7 (Testing, Documentation, Release)
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gate 1: Requirement Completeness
|
|
3
|
+
*
|
|
4
|
+
* Validates that all requirements are properly mapped to tasks/phases
|
|
5
|
+
* and have clear acceptance criteria in Given-When-Then format.
|
|
6
|
+
*
|
|
7
|
+
* Checks:
|
|
8
|
+
* 1. All REQ-IDs are mapped to tasks or phases
|
|
9
|
+
* 2. Acceptance criteria exist and follow Given-When-Then format
|
|
10
|
+
* 3. Returns structured errors for unmapped or incomplete requirements
|
|
11
|
+
*
|
|
12
|
+
* @module gates/gate-01-requirement
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const { z } = require('zod');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Zod schema for a single requirement
|
|
19
|
+
* @type {z.ZodSchema}
|
|
20
|
+
*/
|
|
21
|
+
const requirementSchema = z.object({
|
|
22
|
+
/** Unique requirement identifier (e.g., 'REQ-001', 'GRAPH-01') */
|
|
23
|
+
id: z.string().min(1, 'Requirement ID is required'),
|
|
24
|
+
/** Human-readable requirement description */
|
|
25
|
+
description: z.string().min(1, 'Requirement description is required'),
|
|
26
|
+
/** Acceptance criteria array (each should follow Given-When-Then format) */
|
|
27
|
+
acceptanceCriteria: z.array(z.string()).min(1, 'At least one acceptance criterion is required'),
|
|
28
|
+
/** Optional: Array of task IDs that implement this requirement */
|
|
29
|
+
mappedTasks: z.array(z.string()).optional(),
|
|
30
|
+
/** Optional: Array of phase IDs that cover this requirement */
|
|
31
|
+
mappedPhases: z.array(z.string()).optional(),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Zod schema for a single task
|
|
36
|
+
* @type {z.ZodSchema}
|
|
37
|
+
*/
|
|
38
|
+
const taskSchema = z.object({
|
|
39
|
+
/** Unique task identifier */
|
|
40
|
+
id: z.string(),
|
|
41
|
+
/** Task name/title */
|
|
42
|
+
name: z.string(),
|
|
43
|
+
/** Optional: Requirements this task addresses */
|
|
44
|
+
requirements: z.array(z.string()).optional(),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Zod schema for a single phase
|
|
49
|
+
* @type {z.ZodSchema}
|
|
50
|
+
*/
|
|
51
|
+
const phaseSchema = z.object({
|
|
52
|
+
/** Unique phase identifier */
|
|
53
|
+
id: z.string(),
|
|
54
|
+
/** Phase name/title */
|
|
55
|
+
name: z.string(),
|
|
56
|
+
/** Optional: Requirements this phase covers */
|
|
57
|
+
requirements: z.array(z.string()).optional(),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Zod schema for the gate context
|
|
62
|
+
* @type {z.ZodSchema}
|
|
63
|
+
*/
|
|
64
|
+
const gateContextSchema = z.object({
|
|
65
|
+
/** Array of all requirements to validate */
|
|
66
|
+
requirements: z.array(requirementSchema),
|
|
67
|
+
/** Optional: Array of tasks for mapping validation */
|
|
68
|
+
tasks: z.array(taskSchema).optional(),
|
|
69
|
+
/** Optional: Array of phases for mapping validation */
|
|
70
|
+
phases: z.array(phaseSchema).optional(),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Check if acceptance criteria follow Given-When-Then format
|
|
75
|
+
*
|
|
76
|
+
* Accepts variations:
|
|
77
|
+
* - "Given X, When Y, Then Z" (single line)
|
|
78
|
+
* - "Given X\nWhen Y\nThen Z" (multi-line)
|
|
79
|
+
* - "Given: X\nWhen: Y\nThen: Z" (with colons)
|
|
80
|
+
* - Separate "Given...", "When...", "Then..." entries
|
|
81
|
+
*
|
|
82
|
+
* @param {string[]} acceptanceCriteria - Array of acceptance criteria strings
|
|
83
|
+
* @returns {{ valid: boolean, missingComponents: string[], suggestion: string }}
|
|
84
|
+
*/
|
|
85
|
+
function checkGivenWhenThenFormat(acceptanceCriteria) {
|
|
86
|
+
const result = {
|
|
87
|
+
valid: true,
|
|
88
|
+
missingComponents: [],
|
|
89
|
+
suggestion: '',
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
if (!acceptanceCriteria || acceptanceCriteria.length === 0) {
|
|
93
|
+
result.valid = false;
|
|
94
|
+
result.missingComponents = ['Given', 'When', 'Then'];
|
|
95
|
+
result.suggestion = 'Add acceptance criteria in Given-When-Then format';
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Combine all criteria into single text for analysis
|
|
100
|
+
const fullText = acceptanceCriteria.join('\n').toLowerCase();
|
|
101
|
+
|
|
102
|
+
// Check for Given-When-Then components
|
|
103
|
+
const hasGiven = /given[:\s]/.test(fullText);
|
|
104
|
+
const hasWhen = /when[:\s]/.test(fullText);
|
|
105
|
+
const hasThen = /then[:\s]/.test(fullText);
|
|
106
|
+
|
|
107
|
+
if (!hasGiven) {
|
|
108
|
+
result.missingComponents.push('Given');
|
|
109
|
+
}
|
|
110
|
+
if (!hasWhen) {
|
|
111
|
+
result.missingComponents.push('When');
|
|
112
|
+
}
|
|
113
|
+
if (!hasThen) {
|
|
114
|
+
result.missingComponents.push('Then');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (result.missingComponents.length > 0) {
|
|
118
|
+
result.valid = false;
|
|
119
|
+
result.suggestion = `Missing BDD components: ${result.missingComponents.join(', ')}. ` +
|
|
120
|
+
'Format: "Given [context], When [action], Then [expected outcome]"';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Extract REQ-IDs from a text string
|
|
128
|
+
* Matches patterns like: REQ-001, GRAPH-02, GATE-01, etc.
|
|
129
|
+
*
|
|
130
|
+
* @param {string} text - Text to search for requirement IDs
|
|
131
|
+
* @returns {string[]} Array of found requirement IDs
|
|
132
|
+
*/
|
|
133
|
+
function extractRequirementIds(text) {
|
|
134
|
+
if (!text) return [];
|
|
135
|
+
|
|
136
|
+
// Match patterns like REQ-001, GRAPH-02, GATE-01, etc.
|
|
137
|
+
const pattern = /\b([A-Z]+-\d+)\b/g;
|
|
138
|
+
const matches = text.match(pattern);
|
|
139
|
+
return matches ? [...new Set(matches)] : [];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Build a map of requirement IDs to their mappings from tasks
|
|
144
|
+
*
|
|
145
|
+
* @param {Array} tasks - Array of task objects
|
|
146
|
+
* @returns {Map<string, Set<string>>} Map of reqId -> Set of task IDs
|
|
147
|
+
*/
|
|
148
|
+
function buildRequirementTaskMap(tasks) {
|
|
149
|
+
const map = new Map();
|
|
150
|
+
|
|
151
|
+
if (!tasks || !Array.isArray(tasks)) {
|
|
152
|
+
return map;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
for (const task of tasks) {
|
|
156
|
+
const reqs = task.requirements || [];
|
|
157
|
+
for (const reqId of reqs) {
|
|
158
|
+
if (!map.has(reqId)) {
|
|
159
|
+
map.set(reqId, new Set());
|
|
160
|
+
}
|
|
161
|
+
map.get(reqId).add(task.id);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Also check task name and description for implicit references
|
|
165
|
+
const implicitRefs = extractRequirementIds(`${task.name} ${task.description || ''}`);
|
|
166
|
+
for (const reqId of implicitRefs) {
|
|
167
|
+
if (!map.has(reqId)) {
|
|
168
|
+
map.set(reqId, new Set());
|
|
169
|
+
}
|
|
170
|
+
map.get(reqId).add(task.id);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return map;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Build a map of requirement IDs to their mappings from phases
|
|
179
|
+
*
|
|
180
|
+
* @param {Array} phases - Array of phase objects
|
|
181
|
+
* @returns {Map<string, Set<string>>} Map of reqId -> Set of phase IDs
|
|
182
|
+
*/
|
|
183
|
+
function buildRequirementPhaseMap(phases) {
|
|
184
|
+
const map = new Map();
|
|
185
|
+
|
|
186
|
+
if (!phases || !Array.isArray(phases)) {
|
|
187
|
+
return map;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
for (const phase of phases) {
|
|
191
|
+
const reqs = phase.requirements || [];
|
|
192
|
+
for (const reqId of reqs) {
|
|
193
|
+
if (!map.has(reqId)) {
|
|
194
|
+
map.set(reqId, new Set());
|
|
195
|
+
}
|
|
196
|
+
map.get(reqId).add(phase.id);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Also check phase name and description for implicit references
|
|
200
|
+
const implicitRefs = extractRequirementIds(`${phase.name} ${phase.description || ''}`);
|
|
201
|
+
for (const reqId of implicitRefs) {
|
|
202
|
+
if (!map.has(reqId)) {
|
|
203
|
+
map.set(reqId, new Set());
|
|
204
|
+
}
|
|
205
|
+
map.get(reqId).add(phase.id);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return map;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Gate 1 Executor: Requirement Completeness Check
|
|
214
|
+
*
|
|
215
|
+
* Validates:
|
|
216
|
+
* 1. All requirements have mapped tasks or phases
|
|
217
|
+
* 2. All requirements have acceptance criteria in Given-When-Then format
|
|
218
|
+
*
|
|
219
|
+
* @param {Object} context - Gate context (validated against gateContextSchema)
|
|
220
|
+
* @param {Array} context.requirements - Array of requirement objects
|
|
221
|
+
* @param {Array} [context.tasks] - Optional array of task objects
|
|
222
|
+
* @param {Array} [context.phases] - Optional array of phase objects
|
|
223
|
+
* @returns {Promise<{ passed: boolean, errors: Array<{path: string, message: string}>, warnings: string[] }>}
|
|
224
|
+
*/
|
|
225
|
+
async function executeGate1(context) {
|
|
226
|
+
const errors = [];
|
|
227
|
+
const warnings = [];
|
|
228
|
+
|
|
229
|
+
// Build mapping indices
|
|
230
|
+
const taskMap = buildRequirementTaskMap(context.tasks);
|
|
231
|
+
const phaseMap = buildRequirementPhaseMap(context.phases);
|
|
232
|
+
|
|
233
|
+
// Check each requirement
|
|
234
|
+
for (let i = 0; i < context.requirements.length; i++) {
|
|
235
|
+
const req = context.requirements[i];
|
|
236
|
+
const reqPath = `requirements[${i}]`;
|
|
237
|
+
|
|
238
|
+
// Check 1: Requirement mapping
|
|
239
|
+
const mappedToTasks = taskMap.has(req.id);
|
|
240
|
+
const mappedToPhases = phaseMap.has(req.id);
|
|
241
|
+
const hasExplicitMapping = (req.mappedTasks && req.mappedTasks.length > 0) ||
|
|
242
|
+
(req.mappedPhases && req.mappedPhases.length > 0);
|
|
243
|
+
|
|
244
|
+
if (!mappedToTasks && !mappedToPhases && !hasExplicitMapping) {
|
|
245
|
+
errors.push({
|
|
246
|
+
path: `${reqPath}.id`,
|
|
247
|
+
message: `Requirement '${req.id}' is not mapped to any task or phase. ` +
|
|
248
|
+
`Add 'requirements: ["${req.id}"]' to a task/phase frontmatter or ` +
|
|
249
|
+
`add explicit mappedTasks/mappedPhases array.`,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Check 2: Acceptance criteria format
|
|
254
|
+
const formatCheck = checkGivenWhenThenFormat(req.acceptanceCriteria);
|
|
255
|
+
if (!formatCheck.valid) {
|
|
256
|
+
errors.push({
|
|
257
|
+
path: `${reqPath}.acceptanceCriteria`,
|
|
258
|
+
message: `Requirement '${req.id}' has acceptance criteria that don't follow ` +
|
|
259
|
+
`Given-When-Then format. ${formatCheck.suggestion}`,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Check 3: Acceptance criteria specificity (warning)
|
|
264
|
+
for (let j = 0; j < req.acceptanceCriteria.length; j++) {
|
|
265
|
+
const criterion = req.acceptanceCriteria[j];
|
|
266
|
+
if (criterion.length < 20) {
|
|
267
|
+
warnings.push(
|
|
268
|
+
`${reqPath}.acceptanceCriteria[${j}]: Criterion for '${req.id}' is very short ` +
|
|
269
|
+
`(${criterion.length} chars). Consider adding more specific, testable criteria.`
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
passed: errors.length === 0,
|
|
277
|
+
errors,
|
|
278
|
+
warnings,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Create and register Gate 1 with a QualityGate instance
|
|
284
|
+
*
|
|
285
|
+
* @param {QualityGate} gateCoordinator - QualityGate coordinator instance
|
|
286
|
+
* @returns {void}
|
|
287
|
+
*/
|
|
288
|
+
function registerGate1(gateCoordinator) {
|
|
289
|
+
gateCoordinator.registerGate('gate-01-requirement', gateContextSchema, executeGate1);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
module.exports = {
|
|
293
|
+
executeGate1,
|
|
294
|
+
registerGate1,
|
|
295
|
+
requirementSchema,
|
|
296
|
+
taskSchema,
|
|
297
|
+
phaseSchema,
|
|
298
|
+
gateContextSchema,
|
|
299
|
+
checkGivenWhenThenFormat,
|
|
300
|
+
extractRequirementIds,
|
|
301
|
+
buildRequirementTaskMap,
|
|
302
|
+
buildRequirementPhaseMap,
|
|
303
|
+
};
|