@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,272 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Gate Executor — Quality gate execution coordinator
|
|
5
|
+
*
|
|
6
|
+
* Executes all registered quality gates and reports results.
|
|
7
|
+
* Supports bypass with audit trail.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node gate-executor.cjs --pre-commit
|
|
11
|
+
* node gate-executor.cjs --status
|
|
12
|
+
* node gate-executor.cjs --bypass "reason"
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const { execSync } = require('child_process');
|
|
18
|
+
const { QualityGate } = require('./quality-gate.cjs');
|
|
19
|
+
const { z } = require('zod');
|
|
20
|
+
|
|
21
|
+
const AUDIT_FILE = path.join(process.cwd(), '.planning', 'gate-audit.json');
|
|
22
|
+
const STATUS_FILE = path.join(process.cwd(), '.planning', 'quality-status.json');
|
|
23
|
+
|
|
24
|
+
// Initialize quality gate coordinator
|
|
25
|
+
const qg = new QualityGate();
|
|
26
|
+
|
|
27
|
+
// Register standard gates
|
|
28
|
+
|
|
29
|
+
// Test gate
|
|
30
|
+
qg.registerGate('test', z.object({ passRate: z.number().min(0.9) }), async (context) => {
|
|
31
|
+
try {
|
|
32
|
+
execSync('npm test', { stdio: 'pipe', encoding: 'utf8' });
|
|
33
|
+
return { passRate: 1.0 };
|
|
34
|
+
} catch (err) {
|
|
35
|
+
// Try to parse test output for pass rate
|
|
36
|
+
const output = err.stdout || err.stderr || '';
|
|
37
|
+
const match = output.match(/(\d+)%\s+pass/);
|
|
38
|
+
const passRate = match ? parseInt(match[1], 10) / 100 : 0;
|
|
39
|
+
throw new Error(`Tests failed (pass rate: ${(passRate * 100).toFixed(1)}%)`);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Lint gate
|
|
44
|
+
qg.registerGate('lint', z.object({ errorCount: z.number().max(0) }), async () => {
|
|
45
|
+
try {
|
|
46
|
+
execSync('npx eslint . --ext .cjs,.js --max-warnings=0', { stdio: 'pipe', encoding: 'utf8' });
|
|
47
|
+
return { errorCount: 0 };
|
|
48
|
+
} catch (err) {
|
|
49
|
+
const output = err.stdout || err.stderr || '';
|
|
50
|
+
const match = output.match(/(\d+)\s+error/);
|
|
51
|
+
const errorCount = match ? parseInt(match[1], 10) : 1;
|
|
52
|
+
throw new Error(`Linting failed (${errorCount} errors)`);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Security gate
|
|
57
|
+
qg.registerGate('security', z.object({ vulnerabilities: z.number().max(0) }), async () => {
|
|
58
|
+
try {
|
|
59
|
+
execSync('npm audit --production', { stdio: 'pipe', encoding: 'utf8' });
|
|
60
|
+
return { vulnerabilities: 0 };
|
|
61
|
+
} catch (err) {
|
|
62
|
+
const output = err.stdout || err.stderr || '';
|
|
63
|
+
const match = output.match(/found\s+(\d+)\s+vulnerabilit/);
|
|
64
|
+
const vulnerabilities = match ? parseInt(match[1], 10) : 1;
|
|
65
|
+
if (vulnerabilities > 0) {
|
|
66
|
+
console.warn(`[WARN] Found ${vulnerabilities} vulnerabilities`);
|
|
67
|
+
// Don't fail - just warn
|
|
68
|
+
}
|
|
69
|
+
return { vulnerabilities };
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Build gate
|
|
74
|
+
qg.registerGate('build', z.object({ success: z.boolean() }), async () => {
|
|
75
|
+
try {
|
|
76
|
+
execSync('node scripts/build-hooks.js', { stdio: 'pipe', encoding: 'utf8' });
|
|
77
|
+
return { success: true };
|
|
78
|
+
} catch (err) {
|
|
79
|
+
throw new Error('Build failed');
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Documentation gate (JSDoc coverage)
|
|
84
|
+
qg.registerGate('docs', z.object({ jsdocCoverage: z.number().min(0.5) }), async () => {
|
|
85
|
+
// Simple check: count files with JSDoc comments
|
|
86
|
+
const libDir = path.join(process.cwd(), 'bin', 'lib');
|
|
87
|
+
if (!fs.existsSync(libDir)) {
|
|
88
|
+
return { jsdocCoverage: 1.0 };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const files = fs.readdirSync(libDir).filter(f => f.endsWith('.cjs'));
|
|
92
|
+
let withJSDoc = 0;
|
|
93
|
+
|
|
94
|
+
for (const file of files) {
|
|
95
|
+
const content = fs.readFileSync(path.join(libDir, file), 'utf8');
|
|
96
|
+
if (content.includes('/**')) {
|
|
97
|
+
withJSDoc++;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const coverage = files.length > 0 ? withJSDoc / files.length : 1.0;
|
|
102
|
+
return { jsdocCoverage: coverage };
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Load gate status from file
|
|
107
|
+
*/
|
|
108
|
+
function loadStatus() {
|
|
109
|
+
try {
|
|
110
|
+
if (fs.existsSync(STATUS_FILE)) {
|
|
111
|
+
return JSON.parse(fs.readFileSync(STATUS_FILE, 'utf8'));
|
|
112
|
+
}
|
|
113
|
+
} catch (err) {
|
|
114
|
+
// Ignore
|
|
115
|
+
}
|
|
116
|
+
return { gates: {}, lastRun: null };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Save gate status to file
|
|
121
|
+
*/
|
|
122
|
+
function saveStatus(status) {
|
|
123
|
+
try {
|
|
124
|
+
const dir = path.dirname(STATUS_FILE);
|
|
125
|
+
if (!fs.existsSync(dir)) {
|
|
126
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
127
|
+
}
|
|
128
|
+
fs.writeFileSync(STATUS_FILE, JSON.stringify(status, null, 2), 'utf8');
|
|
129
|
+
} catch (err) {
|
|
130
|
+
console.error('Failed to save status:', err.message);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Record gate bypass to audit trail
|
|
136
|
+
*/
|
|
137
|
+
function recordBypass(gateId, reason) {
|
|
138
|
+
const audit = {
|
|
139
|
+
gate: gateId,
|
|
140
|
+
action: 'bypass',
|
|
141
|
+
reason,
|
|
142
|
+
bypassedBy: process.env.USER || process.env.USERNAME || 'unknown',
|
|
143
|
+
timestamp: new Date().toISOString()
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
let auditTrail = [];
|
|
147
|
+
try {
|
|
148
|
+
if (fs.existsSync(AUDIT_FILE)) {
|
|
149
|
+
auditTrail = JSON.parse(fs.readFileSync(AUDIT_FILE, 'utf8'));
|
|
150
|
+
}
|
|
151
|
+
} catch (err) {
|
|
152
|
+
// Ignore
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
auditTrail.push(audit);
|
|
156
|
+
fs.writeFileSync(AUDIT_FILE, JSON.stringify(auditTrail, null, 2), 'utf8');
|
|
157
|
+
console.warn(`[GATE BYPASS] ${gateId} bypassed: ${reason}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Main execution
|
|
162
|
+
*/
|
|
163
|
+
async function main() {
|
|
164
|
+
const args = process.argv.slice(2);
|
|
165
|
+
const status = loadStatus();
|
|
166
|
+
|
|
167
|
+
// Check for bypass flag
|
|
168
|
+
const bypassIdx = args.indexOf('--bypass');
|
|
169
|
+
if (bypassIdx !== -1 && args[bypassIdx + 1]) {
|
|
170
|
+
const reason = args[bypassIdx + 1];
|
|
171
|
+
const gateIdx = args.indexOf('--gate');
|
|
172
|
+
if (gateIdx !== -1 && args[gateIdx + 1]) {
|
|
173
|
+
recordBypass(args[gateIdx + 1], reason);
|
|
174
|
+
} else {
|
|
175
|
+
console.error('Error: --bypass requires --gate <gate-id>');
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Execute all gates
|
|
181
|
+
const results = {};
|
|
182
|
+
const startTime = Date.now();
|
|
183
|
+
|
|
184
|
+
console.log('Executing quality gates...');
|
|
185
|
+
console.log('');
|
|
186
|
+
|
|
187
|
+
for (const [gateId] of qg.gates || []) {
|
|
188
|
+
try {
|
|
189
|
+
const result = await qg.execute(gateId);
|
|
190
|
+
results[gateId] = {
|
|
191
|
+
passed: result.passed,
|
|
192
|
+
timestamp: new Date().toISOString(),
|
|
193
|
+
errors: result.errors || [],
|
|
194
|
+
warnings: result.warnings || []
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const icon = result.passed ? '✓' : '✗';
|
|
198
|
+
console.log(`${icon} ${gateId}`);
|
|
199
|
+
|
|
200
|
+
if (result.warnings && result.warnings.length > 0) {
|
|
201
|
+
result.warnings.forEach(w => console.warn(` ⚠ ${w}`));
|
|
202
|
+
}
|
|
203
|
+
} catch (err) {
|
|
204
|
+
results[gateId] = {
|
|
205
|
+
passed: false,
|
|
206
|
+
timestamp: new Date().toISOString(),
|
|
207
|
+
errors: [err.message],
|
|
208
|
+
warnings: []
|
|
209
|
+
};
|
|
210
|
+
console.log(`✗ ${gateId}: ${err.message}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const duration = Date.now() - startTime;
|
|
215
|
+
status.lastRun = new Date().toISOString();
|
|
216
|
+
status.gates = results;
|
|
217
|
+
status.duration = duration;
|
|
218
|
+
saveStatus(status);
|
|
219
|
+
|
|
220
|
+
console.log('');
|
|
221
|
+
console.log(`Quality gates completed in ${(duration / 1000).toFixed(1)}s`);
|
|
222
|
+
|
|
223
|
+
// Check for failures
|
|
224
|
+
const failed = Object.entries(results).filter(([_, r]) => !r.passed);
|
|
225
|
+
if (failed.length > 0) {
|
|
226
|
+
console.log('');
|
|
227
|
+
console.log('Failed gates:');
|
|
228
|
+
failed.forEach(([gateId, result]) => {
|
|
229
|
+
console.log(` - ${gateId}: ${result.errors.join(', ')}`);
|
|
230
|
+
});
|
|
231
|
+
console.log('');
|
|
232
|
+
console.log('Use --bypass "reason" to bypass a gate (requires audit trail)');
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
console.log('');
|
|
237
|
+
console.log('All quality gates passed ✓');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Handle pre-commit mode
|
|
241
|
+
if (process.argv.includes('--pre-commit')) {
|
|
242
|
+
main().catch(err => {
|
|
243
|
+
console.error('Gate execution failed:', err.message);
|
|
244
|
+
process.exit(1);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Handle status mode
|
|
249
|
+
if (process.argv.includes('--status')) {
|
|
250
|
+
const status = loadStatus();
|
|
251
|
+
console.log('');
|
|
252
|
+
console.log('Quality Gate Status');
|
|
253
|
+
console.log('═══════════════════');
|
|
254
|
+
console.log('');
|
|
255
|
+
|
|
256
|
+
if (!status.lastRun) {
|
|
257
|
+
console.log('No gate runs recorded');
|
|
258
|
+
} else {
|
|
259
|
+
console.log(`Last run: ${new Date(status.lastRun).toLocaleString()}`);
|
|
260
|
+
console.log(`Duration: ${status.duration || 0}ms`);
|
|
261
|
+
console.log('');
|
|
262
|
+
|
|
263
|
+
const passed = Object.values(status.gates).filter(g => g.passed).length;
|
|
264
|
+
const failed = Object.values(status.gates).filter(g => !g.passed).length;
|
|
265
|
+
console.log(`Results: ${passed} passed, ${failed} failed`);
|
|
266
|
+
}
|
|
267
|
+
console.log('');
|
|
268
|
+
process.exit(0);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Default: don't run, just export
|
|
272
|
+
module.exports = { QualityGate, recordBypass, loadStatus, saveStatus };
|
|
@@ -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)
|