mindforge-cc 1.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.
Files changed (324) hide show
  1. package/.agent/CLAUDE.md +462 -0
  2. package/.agent/forge/help.md +7 -0
  3. package/.agent/forge/init-project.md +32 -0
  4. package/.agent/forge/plan-phase.md +30 -0
  5. package/.agent/mindforge/approve.md +18 -0
  6. package/.agent/mindforge/audit.md +30 -0
  7. package/.agent/mindforge/benchmark.md +33 -0
  8. package/.agent/mindforge/complete-milestone.md +18 -0
  9. package/.agent/mindforge/debug.md +126 -0
  10. package/.agent/mindforge/discuss-phase.md +138 -0
  11. package/.agent/mindforge/execute-phase.md +165 -0
  12. package/.agent/mindforge/health.md +21 -0
  13. package/.agent/mindforge/help.md +23 -0
  14. package/.agent/mindforge/init-org.md +131 -0
  15. package/.agent/mindforge/init-project.md +155 -0
  16. package/.agent/mindforge/install-skill.md +15 -0
  17. package/.agent/mindforge/map-codebase.md +298 -0
  18. package/.agent/mindforge/metrics.md +22 -0
  19. package/.agent/mindforge/migrate.md +40 -0
  20. package/.agent/mindforge/milestone.md +12 -0
  21. package/.agent/mindforge/next.md +105 -0
  22. package/.agent/mindforge/plan-phase.md +125 -0
  23. package/.agent/mindforge/plugins.md +40 -0
  24. package/.agent/mindforge/pr-review.md +41 -0
  25. package/.agent/mindforge/profile-team.md +23 -0
  26. package/.agent/mindforge/publish-skill.md +19 -0
  27. package/.agent/mindforge/quick.md +135 -0
  28. package/.agent/mindforge/release.md +10 -0
  29. package/.agent/mindforge/retrospective.md +26 -0
  30. package/.agent/mindforge/review.md +157 -0
  31. package/.agent/mindforge/security-scan.md +233 -0
  32. package/.agent/mindforge/ship.md +100 -0
  33. package/.agent/mindforge/skills.md +141 -0
  34. package/.agent/mindforge/status.md +104 -0
  35. package/.agent/mindforge/sync-confluence.md +11 -0
  36. package/.agent/mindforge/sync-jira.md +12 -0
  37. package/.agent/mindforge/tokens.md +8 -0
  38. package/.agent/mindforge/update.md +42 -0
  39. package/.agent/mindforge/verify-phase.md +62 -0
  40. package/.agent/mindforge/workspace.md +29 -0
  41. package/.claude/CLAUDE.md +462 -0
  42. package/.claude/commands/forge/help.md +7 -0
  43. package/.claude/commands/forge/init-project.md +32 -0
  44. package/.claude/commands/forge/plan-phase.md +30 -0
  45. package/.claude/commands/mindforge/approve.md +18 -0
  46. package/.claude/commands/mindforge/audit.md +30 -0
  47. package/.claude/commands/mindforge/benchmark.md +33 -0
  48. package/.claude/commands/mindforge/complete-milestone.md +18 -0
  49. package/.claude/commands/mindforge/debug.md +126 -0
  50. package/.claude/commands/mindforge/discuss-phase.md +138 -0
  51. package/.claude/commands/mindforge/execute-phase.md +165 -0
  52. package/.claude/commands/mindforge/health.md +21 -0
  53. package/.claude/commands/mindforge/help.md +23 -0
  54. package/.claude/commands/mindforge/init-org.md +131 -0
  55. package/.claude/commands/mindforge/init-project.md +155 -0
  56. package/.claude/commands/mindforge/install-skill.md +15 -0
  57. package/.claude/commands/mindforge/map-codebase.md +298 -0
  58. package/.claude/commands/mindforge/metrics.md +22 -0
  59. package/.claude/commands/mindforge/migrate.md +40 -0
  60. package/.claude/commands/mindforge/milestone.md +12 -0
  61. package/.claude/commands/mindforge/next.md +105 -0
  62. package/.claude/commands/mindforge/plan-phase.md +125 -0
  63. package/.claude/commands/mindforge/plugins.md +40 -0
  64. package/.claude/commands/mindforge/pr-review.md +41 -0
  65. package/.claude/commands/mindforge/profile-team.md +23 -0
  66. package/.claude/commands/mindforge/publish-skill.md +19 -0
  67. package/.claude/commands/mindforge/quick.md +135 -0
  68. package/.claude/commands/mindforge/release.md +10 -0
  69. package/.claude/commands/mindforge/retrospective.md +26 -0
  70. package/.claude/commands/mindforge/review.md +157 -0
  71. package/.claude/commands/mindforge/security-scan.md +233 -0
  72. package/.claude/commands/mindforge/ship.md +100 -0
  73. package/.claude/commands/mindforge/skills.md +141 -0
  74. package/.claude/commands/mindforge/status.md +104 -0
  75. package/.claude/commands/mindforge/sync-confluence.md +11 -0
  76. package/.claude/commands/mindforge/sync-jira.md +12 -0
  77. package/.claude/commands/mindforge/tokens.md +8 -0
  78. package/.claude/commands/mindforge/update.md +42 -0
  79. package/.claude/commands/mindforge/verify-phase.md +62 -0
  80. package/.claude/commands/mindforge/workspace.md +29 -0
  81. package/.forge/org/CONVENTIONS.md +0 -0
  82. package/.forge/org/ORG.md +0 -0
  83. package/.forge/org/SECURITY.md +0 -0
  84. package/.forge/org/TOOLS.md +0 -0
  85. package/.forge/personas/analyst.md +0 -0
  86. package/.forge/personas/architect.md +0 -0
  87. package/.forge/personas/debug-specialist.md +0 -0
  88. package/.forge/personas/developer.md +26 -0
  89. package/.forge/personas/qa-engineer.md +0 -0
  90. package/.forge/personas/release-manager.md +0 -0
  91. package/.forge/personas/security-reviewer.md +33 -0
  92. package/.forge/personas/tech-writer.md +0 -0
  93. package/.forge/skills/api-design/SKILL.md +0 -0
  94. package/.forge/skills/code-quality/SKILL.md +0 -0
  95. package/.forge/skills/documentation/SKILL.md +0 -0
  96. package/.forge/skills/security-review/SKILL.md +23 -0
  97. package/.forge/skills/testing-standards/SKILL.md +27 -0
  98. package/.github/workflows/mindforge-ci.yml +224 -0
  99. package/.gitlab-ci-mindforge.yml +18 -0
  100. package/.mindforge/MINDFORGE-SCHEMA.json +165 -0
  101. package/.mindforge/audit/AUDIT-SCHEMA.md +451 -0
  102. package/.mindforge/ci/ci-config-schema.md +21 -0
  103. package/.mindforge/ci/ci-mode.md +179 -0
  104. package/.mindforge/ci/github-actions-adapter.md +224 -0
  105. package/.mindforge/ci/gitlab-ci-adapter.md +31 -0
  106. package/.mindforge/ci/jenkins-adapter.md +44 -0
  107. package/.mindforge/distribution/registry-client.md +166 -0
  108. package/.mindforge/distribution/registry-schema.md +96 -0
  109. package/.mindforge/distribution/skill-publisher.md +44 -0
  110. package/.mindforge/distribution/skill-validator.md +74 -0
  111. package/.mindforge/engine/compaction-protocol.md +182 -0
  112. package/.mindforge/engine/context-injector.md +128 -0
  113. package/.mindforge/engine/dependency-parser.md +113 -0
  114. package/.mindforge/engine/skills/conflict-resolver.md +69 -0
  115. package/.mindforge/engine/skills/loader.md +184 -0
  116. package/.mindforge/engine/skills/registry.md +98 -0
  117. package/.mindforge/engine/skills/versioning.md +75 -0
  118. package/.mindforge/engine/verification-pipeline.md +111 -0
  119. package/.mindforge/engine/wave-executor.md +235 -0
  120. package/.mindforge/governance/GOVERNANCE-CONFIG.md +17 -0
  121. package/.mindforge/governance/approval-workflow.md +37 -0
  122. package/.mindforge/governance/change-classifier.md +63 -0
  123. package/.mindforge/governance/compliance-gates.md +31 -0
  124. package/.mindforge/integrations/confluence.md +27 -0
  125. package/.mindforge/integrations/connection-manager.md +163 -0
  126. package/.mindforge/integrations/github.md +25 -0
  127. package/.mindforge/integrations/gitlab.md +13 -0
  128. package/.mindforge/integrations/jira.md +102 -0
  129. package/.mindforge/integrations/slack.md +41 -0
  130. package/.mindforge/intelligence/antipattern-detector.md +75 -0
  131. package/.mindforge/intelligence/difficulty-scorer.md +55 -0
  132. package/.mindforge/intelligence/health-engine.md +208 -0
  133. package/.mindforge/intelligence/skill-gap-analyser.md +40 -0
  134. package/.mindforge/intelligence/smart-compaction.md +71 -0
  135. package/.mindforge/metrics/METRICS-SCHEMA.md +42 -0
  136. package/.mindforge/metrics/quality-tracker.md +32 -0
  137. package/.mindforge/monorepo/cross-package-planner.md +114 -0
  138. package/.mindforge/monorepo/dependency-graph-builder.md +32 -0
  139. package/.mindforge/monorepo/workspace-detector.md +129 -0
  140. package/.mindforge/org/CONVENTIONS.md +62 -0
  141. package/.mindforge/org/ORG.md +51 -0
  142. package/.mindforge/org/SECURITY.md +50 -0
  143. package/.mindforge/org/TOOLS.md +53 -0
  144. package/.mindforge/org/integrations/INTEGRATIONS-CONFIG.md +58 -0
  145. package/.mindforge/org/skills/MANIFEST.md +38 -0
  146. package/.mindforge/personas/analyst.md +52 -0
  147. package/.mindforge/personas/architect.md +75 -0
  148. package/.mindforge/personas/debug-specialist.md +52 -0
  149. package/.mindforge/personas/developer.md +85 -0
  150. package/.mindforge/personas/overrides/README.md +85 -0
  151. package/.mindforge/personas/qa-engineer.md +61 -0
  152. package/.mindforge/personas/release-manager.md +76 -0
  153. package/.mindforge/personas/security-reviewer.md +91 -0
  154. package/.mindforge/personas/tech-writer.md +51 -0
  155. package/.mindforge/plugins/PLUGINS-MANIFEST.md +23 -0
  156. package/.mindforge/plugins/plugin-loader.md +93 -0
  157. package/.mindforge/plugins/plugin-registry.md +44 -0
  158. package/.mindforge/plugins/plugin-schema.md +68 -0
  159. package/.mindforge/pr-review/ai-reviewer.md +266 -0
  160. package/.mindforge/pr-review/finding-formatter.md +46 -0
  161. package/.mindforge/pr-review/review-prompt-templates.md +44 -0
  162. package/.mindforge/production/compatibility-layer.md +39 -0
  163. package/.mindforge/production/migration-engine.md +52 -0
  164. package/.mindforge/production/production-checklist.md +165 -0
  165. package/.mindforge/production/token-optimiser.md +68 -0
  166. package/.mindforge/skills/accessibility/SKILL.md +106 -0
  167. package/.mindforge/skills/api-design/SKILL.md +98 -0
  168. package/.mindforge/skills/code-quality/SKILL.md +88 -0
  169. package/.mindforge/skills/data-privacy/SKILL.md +126 -0
  170. package/.mindforge/skills/database-patterns/SKILL.md +192 -0
  171. package/.mindforge/skills/documentation/SKILL.md +91 -0
  172. package/.mindforge/skills/incident-response/SKILL.md +180 -0
  173. package/.mindforge/skills/performance/SKILL.md +120 -0
  174. package/.mindforge/skills/security-review/SKILL.md +83 -0
  175. package/.mindforge/skills/testing-standards/SKILL.md +97 -0
  176. package/.mindforge/team/TEAM-PROFILE.md +42 -0
  177. package/.mindforge/team/multi-handoff.md +23 -0
  178. package/.mindforge/team/profiles/README.md +13 -0
  179. package/.mindforge/team/session-merger.md +18 -0
  180. package/.planning/ARCHITECTURE.md +0 -0
  181. package/.planning/AUDIT.jsonl +0 -0
  182. package/.planning/HANDOFF.json +28 -0
  183. package/.planning/PROJECT.md +33 -0
  184. package/.planning/RELEASE-CHECKLIST.md +68 -0
  185. package/.planning/REQUIREMENTS.md +0 -0
  186. package/.planning/ROADMAP.md +0 -0
  187. package/.planning/STATE.md +31 -0
  188. package/.planning/approvals/.gitkeep +1 -0
  189. package/.planning/archive/.gitkeep +1 -0
  190. package/.planning/audit-archive/.gitkeep +1 -0
  191. package/.planning/decisions/.gitkeep +0 -0
  192. package/.planning/decisions/ADR-001-handoff-tracking.md +41 -0
  193. package/.planning/decisions/ADR-002-markdown-commands.md +46 -0
  194. package/.planning/decisions/ADR-003-skills-trigger-model.md +37 -0
  195. package/.planning/decisions/ADR-004-wave-parallelism-model.md +45 -0
  196. package/.planning/decisions/ADR-005-append-only-audit-log.md +51 -0
  197. package/.planning/decisions/ADR-006-tiered-skills-system.md +22 -0
  198. package/.planning/decisions/ADR-007-trigger-keyword-model.md +22 -0
  199. package/.planning/decisions/ADR-008-just-in-time-skill-loading.md +29 -0
  200. package/.planning/decisions/ADR-009-enterprise-integration-retry-policy.md +8 -0
  201. package/.planning/decisions/ADR-010-governance-tier-escalation.md +8 -0
  202. package/.planning/decisions/ADR-011-multi-developer-handoff-contract.md +8 -0
  203. package/.planning/decisions/ADR-012-intelligence-feedback-loops.md +19 -0
  204. package/.planning/decisions/ADR-013-mindforge-md-constitution.md +16 -0
  205. package/.planning/decisions/ADR-014-metrics-as-signals-not-evaluation.md +15 -0
  206. package/.planning/decisions/ADR-015-npm-based-skill-registry.md +26 -0
  207. package/.planning/decisions/ADR-016-ci-exit-code-0-on-timeout.md +27 -0
  208. package/.planning/decisions/ADR-017-sdk-localhost-only.md +28 -0
  209. package/.planning/decisions/ADR-018-installer-self-install-detection.md +15 -0
  210. package/.planning/decisions/ADR-019-self-update-scope-preservation.md +14 -0
  211. package/.planning/decisions/ADR-020-v1.0.0-stable-interface-contract.md +23 -0
  212. package/.planning/jira-sync.json +9 -0
  213. package/.planning/milestones/.gitkeep +1 -0
  214. package/.planning/phases/day1/REVIEW-DAY1.md +50 -0
  215. package/.planning/phases/day1/SECURITY-REVIEW-DAY1.md +15 -0
  216. package/.planning/phases/day2/REVIEW-DAY2.md +521 -0
  217. package/.planning/phases/day3/REVIEW-DAY3.md +234 -0
  218. package/.planning/slack-threads.json +6 -0
  219. package/CHANGELOG.md +175 -0
  220. package/LICENSE +21 -0
  221. package/MINDFORGE.md +76 -0
  222. package/README.md +182 -0
  223. package/RELEASENOTES.md +41 -0
  224. package/SECURITY.md +4 -0
  225. package/bin/install.js +120 -0
  226. package/bin/installer-core.js +292 -0
  227. package/bin/migrations/0.1.0-to-0.5.0.js +37 -0
  228. package/bin/migrations/0.5.0-to-0.6.0.js +17 -0
  229. package/bin/migrations/0.6.0-to-1.0.0.js +100 -0
  230. package/bin/migrations/migrate.js +151 -0
  231. package/bin/migrations/schema-versions.js +64 -0
  232. package/bin/updater/changelog-fetcher.js +62 -0
  233. package/bin/updater/self-update.js +169 -0
  234. package/bin/updater/version-comparator.js +68 -0
  235. package/bin/validate-config.js +92 -0
  236. package/bin/wizard/config-generator.js +112 -0
  237. package/bin/wizard/environment-detector.js +76 -0
  238. package/bin/wizard/setup-wizard.js +237 -0
  239. package/docs/Context/Master-Context.md +701 -0
  240. package/docs/architecture/README.md +35 -0
  241. package/docs/architecture/decision-records-index.md +26 -0
  242. package/docs/ci-cd-integration.md +30 -0
  243. package/docs/ci-quickstart.md +78 -0
  244. package/docs/commands-reference.md +11 -0
  245. package/docs/contributing/CONTRIBUTING.md +38 -0
  246. package/docs/contributing/plugin-authoring.md +50 -0
  247. package/docs/contributing/skill-authoring.md +41 -0
  248. package/docs/enterprise-setup.md +25 -0
  249. package/docs/faq.md +38 -0
  250. package/docs/getting-started.md +36 -0
  251. package/docs/governance-guide.md +23 -0
  252. package/docs/mindforge-md-reference.md +53 -0
  253. package/docs/monorepo-guide.md +26 -0
  254. package/docs/persona-customisation.md +56 -0
  255. package/docs/quick-verify.md +33 -0
  256. package/docs/reference/audit-events.md +53 -0
  257. package/docs/reference/commands.md +82 -0
  258. package/docs/reference/config-reference.md +64 -0
  259. package/docs/reference/sdk-api.md +48 -0
  260. package/docs/reference/skills-api.md +57 -0
  261. package/docs/release-checklist-guide.md +37 -0
  262. package/docs/requirements.md +29 -0
  263. package/docs/sdk-reference.md +27 -0
  264. package/docs/security/SECURITY.md +42 -0
  265. package/docs/security/penetration-test-results.md +31 -0
  266. package/docs/security/threat-model.md +142 -0
  267. package/docs/skills-authoring-guide.md +119 -0
  268. package/docs/skills-publishing-guide.md +21 -0
  269. package/docs/team-setup-guide.md +21 -0
  270. package/docs/troubleshooting.md +119 -0
  271. package/docs/tutorial.md +195 -0
  272. package/docs/upgrade.md +44 -0
  273. package/docs/user-guide.md +131 -0
  274. package/docs/usp-features.md +214 -0
  275. package/eslint.config.mjs +31 -0
  276. package/examples/starter-project/.planning/AUDIT.jsonl +1 -0
  277. package/examples/starter-project/.planning/HANDOFF.json +23 -0
  278. package/examples/starter-project/.planning/PROJECT.md +27 -0
  279. package/examples/starter-project/.planning/STATE.md +10 -0
  280. package/examples/starter-project/MINDFORGE.md +40 -0
  281. package/examples/starter-project/README.md +14 -0
  282. package/implementation-roadmap/day-1-imp/DAY1-HARDEN.md +823 -0
  283. package/implementation-roadmap/day-1-imp/DAY1-IMPLEMENT.md +2459 -0
  284. package/implementation-roadmap/day-1-imp/DAY1-REVIEW.md +288 -0
  285. package/implementation-roadmap/day-2-imp/DAY2-HARDEN.md +954 -0
  286. package/implementation-roadmap/day-2-imp/DAY2-IMPLEMENT.md +2347 -0
  287. package/implementation-roadmap/day-2-imp/DAY2-REVIEW.md +422 -0
  288. package/implementation-roadmap/day-3-imp/DAY3-HARDEN.md +870 -0
  289. package/implementation-roadmap/day-3-imp/DAY3-IMPLEMENT.md +2798 -0
  290. package/implementation-roadmap/day-3-imp/DAY3-REVIEW.md +484 -0
  291. package/implementation-roadmap/day-4-imp/DAY4-HARDEN.md +1087 -0
  292. package/implementation-roadmap/day-4-imp/DAY4-IMPLEMENT.md +2874 -0
  293. package/implementation-roadmap/day-4-imp/DAY4-REVIEW.md +386 -0
  294. package/implementation-roadmap/day-5-imp/DAY5-HARDEN.md +1078 -0
  295. package/implementation-roadmap/day-5-imp/DAY5-IMPLEMENT.md +3151 -0
  296. package/implementation-roadmap/day-5-imp/DAY5-REVIEW.md +345 -0
  297. package/implementation-roadmap/day-6-imp/DAY6-COMPLETE.md +3919 -0
  298. package/implementation-roadmap/day-7-imp-prod/DAY7-PRODUCTION-FINAL.md +4513 -0
  299. package/package.json +31 -0
  300. package/sdk/README.md +69 -0
  301. package/sdk/eslint.config.mjs +34 -0
  302. package/sdk/package-lock.json +1507 -0
  303. package/sdk/package.json +30 -0
  304. package/sdk/src/client.ts +133 -0
  305. package/sdk/src/commands.ts +63 -0
  306. package/sdk/src/events.ts +166 -0
  307. package/sdk/src/index.ts +22 -0
  308. package/sdk/src/types.ts +87 -0
  309. package/sdk/tsconfig.json +13 -0
  310. package/tests/audit.test.js +206 -0
  311. package/tests/ci-mode.test.js +162 -0
  312. package/tests/compaction.test.js +161 -0
  313. package/tests/distribution.test.js +205 -0
  314. package/tests/e2e.test.js +618 -0
  315. package/tests/governance.test.js +130 -0
  316. package/tests/install.test.js +209 -0
  317. package/tests/integrations.test.js +128 -0
  318. package/tests/intelligence.test.js +117 -0
  319. package/tests/metrics.test.js +96 -0
  320. package/tests/migration.test.js +309 -0
  321. package/tests/production.test.js +416 -0
  322. package/tests/sdk.test.js +200 -0
  323. package/tests/skills-platform.test.js +403 -0
  324. package/tests/wave-engine.test.js +338 -0
@@ -0,0 +1,618 @@
1
+ /**
2
+ * MindForge Day 7 — End-to-End Simulation Tests
3
+ * Simulates complete project workflows using file system operations.
4
+ * No actual Claude API calls — tests the state machine, not the AI.
5
+ *
6
+ * Run: node tests/e2e.test.js
7
+ */
8
+ 'use strict';
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const os = require('os');
13
+ const assert = require('assert');
14
+ let passed = 0, failed = 0;
15
+ const cleanupFailures = [];
16
+
17
+ function test(name, fn) {
18
+ try { fn(); console.log(` ✅ ${name}`); passed++; }
19
+ catch(e) { console.error(` ❌ ${name}\n ${e.message}`); failed++; }
20
+ }
21
+
22
+ // ── Test project factory ───────────────────────────────────────────────────────
23
+ function createTestProject() {
24
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mindforge-e2e-'));
25
+
26
+ function write(relPath, content) {
27
+ const fullPath = path.join(tmpDir, relPath);
28
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
29
+ fs.writeFileSync(fullPath, content, 'utf8');
30
+ return fullPath;
31
+ }
32
+
33
+ function read(relPath) {
34
+ const p = path.join(tmpDir, relPath);
35
+ return fs.existsSync(p) ? fs.readFileSync(p, 'utf8') : null;
36
+ }
37
+
38
+ function exists(relPath) {
39
+ return fs.existsSync(path.join(tmpDir, relPath));
40
+ }
41
+
42
+ function appendAudit(entry) {
43
+ const auditPath = path.join(tmpDir, '.planning', 'AUDIT.jsonl');
44
+ const line = JSON.stringify({
45
+ id: `test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
46
+ timestamp: new Date().toISOString(),
47
+ session_id: 'test-session-001',
48
+ agent: 'mindforge-test',
49
+ ...entry,
50
+ });
51
+ fs.appendFileSync(auditPath, line + '\n');
52
+ }
53
+
54
+ function cleanup() {
55
+ try { fs.rmSync(tmpDir, { recursive: true, force: true }); }
56
+ catch(e) {
57
+ cleanupFailures.push(tmpDir);
58
+ console.warn(` ⚠️ Cleanup warning: ${e.message} (dir: ${tmpDir})`);
59
+ }
60
+ }
61
+
62
+ return { tmpDir, write, read, exists, appendAudit, cleanup };
63
+ }
64
+
65
+ // ── Workflow simulation functions ──────────────────────────────────────────────
66
+
67
+ function initProject(project) {
68
+ const { write } = project;
69
+
70
+ // Core .planning/ files
71
+ write('.planning/PROJECT.md', `# E2E Test Project
72
+
73
+ ## Tech stack
74
+ - Node.js 20 LTS
75
+ - TypeScript 5.x
76
+ - PostgreSQL via Prisma
77
+
78
+ ## v1 scope — IN
79
+ - [x] User authentication (email/password)
80
+ - [x] User profile management
81
+
82
+ ## Success criteria
83
+ All acceptance tests passing. Zero HIGH security findings.
84
+ `);
85
+
86
+ write('.planning/REQUIREMENTS.md', `# Requirements
87
+
88
+ ## Functional requirements
89
+ | ID | Requirement | Acceptance criterion | Scope |
90
+ |---|---|---|---|
91
+ | FR-01 | User login | POST /auth/login returns JWT for valid credentials | v1 |
92
+ | FR-02 | User logout | POST /auth/logout invalidates session | v1 |
93
+ | FR-03 | Profile fetch | GET /users/:id returns profile for authenticated user | v1 |
94
+ `);
95
+
96
+ write('.planning/ARCHITECTURE.md', `# Architecture
97
+
98
+ ## Architectural pattern
99
+ Modular monolith — Express API with Prisma ORM
100
+
101
+ ## Technology stack
102
+ - Runtime: Node.js 20
103
+ - Framework: Express 4.x
104
+ - Database: PostgreSQL 15
105
+
106
+ ## Data model
107
+ **User**: id (UUID), email, passwordHash, createdAt, updatedAt
108
+ `);
109
+
110
+ write('.planning/STATE.md', `# Project State
111
+
112
+ ## Status
113
+ Phase 1 in progress
114
+
115
+ ## Current phase
116
+ Phase 1 — Authentication
117
+
118
+ ## Next action
119
+ Execute Phase 1 plans
120
+ `);
121
+
122
+ write('.planning/HANDOFF.json', JSON.stringify({
123
+ schema_version: '1.0.0',
124
+ plugin_api_version: '1.0.0',
125
+ project: 'E2E Test Project',
126
+ phase: 1,
127
+ plan: null,
128
+ next_task: 'Execute Phase 1 — Authentication',
129
+ blockers: [],
130
+ decisions_needed: [],
131
+ decisions_made: [],
132
+ discoveries: [],
133
+ implicit_knowledge: [],
134
+ quality_signals: [],
135
+ context_refs: ['.planning/PROJECT.md', '.planning/STATE.md'],
136
+ recent_commits: [],
137
+ recent_files: [],
138
+ session_id: 'test-session-001',
139
+ _warning: 'Never store secrets or tokens in this file.',
140
+ updated_at: new Date().toISOString(),
141
+ }, null, 2));
142
+
143
+ write('.planning/AUDIT.jsonl', '');
144
+ project.appendAudit({ event: 'project_initialised', phase: null });
145
+ }
146
+
147
+ function planPhase(project, phaseNum) {
148
+ const { write, appendAudit } = project;
149
+ const phaseDir = `.planning/phases/${phaseNum}`;
150
+
151
+ // Difficulty score
152
+ write(`${phaseDir}/DIFFICULTY-SCORE-${phaseNum}.md`, `# Difficulty Score — Phase ${phaseNum}
153
+ ## Scores
154
+ | Dimension | Score |
155
+ |---|---|
156
+ | Technical | 4/5 |
157
+ | Risk | 5/5 |
158
+ | Ambiguity | 2/5 |
159
+ | Dependencies | 2/5 |
160
+ ## Composite: 3.75 — Challenging
161
+ ## Recommendations: 6 atomic tasks
162
+ `);
163
+
164
+ // Plan file with valid XML
165
+ write(`${phaseDir}/PLAN-${phaseNum}-01.md`, `<task type="auto">
166
+ <n>Implement login endpoint with JWT</n>
167
+ <persona>developer</persona>
168
+ <phase>${phaseNum}</phase>
169
+ <plan>01</plan>
170
+ <dependencies>none</dependencies>
171
+ <files>
172
+ src/auth/login.ts
173
+ src/auth/login.test.ts
174
+ </files>
175
+ <context>
176
+ Skills: security-review (jwt.sign trigger), api-design, testing-standards
177
+ </context>
178
+ <action>
179
+ Create POST /auth/login endpoint. Validate email/password against database.
180
+ Use argon2 for password verification. Return signed JWT on success.
181
+ Return 401 for invalid credentials (no information disclosure).
182
+ </action>
183
+ <verify>npm test -- --testPathPattern=auth.login</verify>
184
+ <done>All login tests passing, argon2 verification working, JWT returned</done>
185
+ </task>`);
186
+
187
+ write(`${phaseDir}/PLAN-${phaseNum}-02.md`, `<task type="auto">
188
+ <n>Implement logout endpoint with session invalidation</n>
189
+ <persona>developer</persona>
190
+ <phase>${phaseNum}</phase>
191
+ <plan>02</plan>
192
+ <dependencies>01</dependencies>
193
+ <files>
194
+ src/auth/logout.ts
195
+ src/auth/logout.test.ts
196
+ </files>
197
+ <context>
198
+ Skills: security-review, testing-standards
199
+ </context>
200
+ <action>
201
+ Create POST /auth/logout endpoint. Invalidate JWT via blocklist in Redis.
202
+ Verify that blocklisted tokens return 401 on subsequent requests.
203
+ </action>
204
+ <verify>npm test -- --testPathPattern=auth.logout</verify>
205
+ <done>Logout invalidates tokens, blocklisted tokens rejected</done>
206
+ </task>`);
207
+
208
+ // Dependency graph
209
+ write(`${phaseDir}/DEPENDENCY-GRAPH-${phaseNum}.md`, `# Dependency Graph — Phase ${phaseNum}
210
+
211
+ ## Wave 1 (independent)
212
+ - Plan 01: Implement login endpoint
213
+
214
+ ## Wave 2 (depends on Wave 1)
215
+ - Plan 02: Implement logout endpoint (requires login implementation)
216
+ `);
217
+
218
+ appendAudit({ event: 'phase_planned', phase: phaseNum, plans_created: 2, waves: 2 });
219
+ }
220
+
221
+ function executeTask(project, phaseNum, planId, commitSha) {
222
+ const { write, appendAudit } = project;
223
+ const phaseDir = `.planning/phases/${phaseNum}`;
224
+
225
+ appendAudit({ event: 'task_started', phase: phaseNum, plan: planId });
226
+
227
+ write(`${phaseDir}/SUMMARY-${phaseNum}-${planId}.md`, `# Summary — Phase ${phaseNum}, Plan ${planId}
228
+ ## Status: Completed ✅
229
+ ## Commit: ${commitSha}
230
+ ## Verify result: PASS
231
+ ## Files modified:
232
+ - src/auth/${planId === '01' ? 'login' : 'logout'}.ts (created)
233
+ - src/auth/${planId === '01' ? 'login' : 'logout'}.test.ts (created, 8 tests)
234
+ `);
235
+
236
+ appendAudit({ event: 'task_completed', phase: phaseNum, plan: planId, commit_sha: commitSha, verify_result: 'pass' });
237
+ }
238
+
239
+ function runSecurityScan(project, phaseNum, findings = []) {
240
+ const { write, appendAudit } = project;
241
+ const phaseDir = `.planning/phases/${phaseNum}`;
242
+
243
+ const criticalCount = findings.filter(f => f.severity === 'CRITICAL').length;
244
+ const highCount = findings.filter(f => f.severity === 'HIGH').length;
245
+
246
+ write(`${phaseDir}/SECURITY-REVIEW-${phaseNum}.md`, `# Security Review — Phase ${phaseNum}
247
+ ## Scan date: ${new Date().toISOString()}
248
+ ## OWASP A01: ${findings.length === 0 ? 'PASS ✅' : 'FINDINGS'}
249
+
250
+ ${findings.map(f => `### ${f.severity}: ${f.description}\nFile: ${f.file}:${f.line}\nRemediation: ${f.remediation}`).join('\n\n')}
251
+
252
+ ## Summary
253
+ - CRITICAL: ${criticalCount}
254
+ - HIGH: ${highCount}
255
+ - Total: ${findings.length}
256
+ ${findings.length === 0 ? '## Verdict: CLEAN ✅' : `## Verdict: ${criticalCount > 0 ? '🔴 BLOCKED' : '⚠️ REVIEW REQUIRED'}`}
257
+ `);
258
+
259
+ appendAudit({ event: 'security_scan_completed', phase: phaseNum, critical: criticalCount, high: highCount });
260
+ }
261
+
262
+ function verifyPhase(project, phaseNum) {
263
+ const { write, appendAudit } = project;
264
+ const phaseDir = `.planning/phases/${phaseNum}`;
265
+
266
+ write(`${phaseDir}/GATE-RESULTS-${phaseNum}.md`, `# Compliance Gate Results — Phase ${phaseNum}
267
+ ## Run at: ${new Date().toISOString()}
268
+ | Gate | Status | Detail |
269
+ |---|---|---|
270
+ | Secret detection | ✅ PASS | 0 patterns found |
271
+ | CRITICAL security findings | ✅ PASS | No open CRITICAL findings |
272
+ | Test suite | ✅ PASS | 16 tests passing |
273
+ | Dependency CVEs | ✅ PASS | 0 HIGH/CRITICAL |
274
+ | GDPR retention | ✅ PASS | data-privacy skill not active |
275
+ ## Overall: ✅ ALL BLOCKING GATES PASSED
276
+ `);
277
+
278
+ write(`${phaseDir}/VERIFICATION-${phaseNum}.md`, `# Verification — Phase ${phaseNum}
279
+ ## Stage 1 — Tests: 16/16 passing ✅
280
+ ## Stage 2 — Requirements:
281
+ | FR-01 | User login | ✅ | src/auth/login.ts:24 |
282
+ | FR-02 | User logout | ✅ | src/auth/logout.ts:18 |
283
+ ## Stage 3 — Type check: PASS ✅
284
+ ## Stage 4 — Security: PASS ✅
285
+ ## Overall: ✅ PHASE VERIFIED
286
+ `);
287
+
288
+ write(`${phaseDir}/UAT-${phaseNum}.md`, `# UAT — Phase ${phaseNum}
289
+ ## Test results
290
+ | # | Deliverable | Result | Notes |
291
+ |---|---|---|---|
292
+ | 1 | POST /auth/login returns JWT | ✅ | Tested with valid+invalid credentials |
293
+ | 2 | POST /auth/logout invalidates session | ✅ | Blocklist verified |
294
+ ## Overall: ✅ ALL UAT PASSED
295
+ `);
296
+
297
+ appendAudit({ event: 'phase_completed', phase: phaseNum, uat_pass_rate: 1.0 });
298
+ }
299
+
300
+ // ── Tests ──────────────────────────────────────────────────────────────────────
301
+ console.log('\nMindForge Day 7 — End-to-End Tests\n');
302
+
303
+ // ── Test 1: Complete greenfield workflow ───────────────────────────────────────
304
+ console.log('Greenfield project workflow:');
305
+ const gf = createTestProject();
306
+
307
+ try {
308
+ test('init-project creates all required .planning/ files', () => {
309
+ initProject(gf);
310
+ const required = ['PROJECT.md', 'REQUIREMENTS.md', 'ARCHITECTURE.md', 'STATE.md', 'HANDOFF.json', 'AUDIT.jsonl'];
311
+ required.forEach(f => assert.ok(gf.exists(`.planning/${f}`), `Missing: ${f}`));
312
+ });
313
+
314
+ test('HANDOFF.json has v1.0.0 schema_version and plugin_api_version', () => {
315
+ const handoff = JSON.parse(gf.read('.planning/HANDOFF.json'));
316
+ assert.strictEqual(handoff.schema_version, '1.0.0');
317
+ assert.strictEqual(handoff.plugin_api_version, '1.0.0');
318
+ assert.ok(handoff._warning, 'Should have _warning field');
319
+ assert.ok(!handoff._warning.toLowerCase().includes('password'), '_warning should not contain password');
320
+ });
321
+
322
+ test('initial AUDIT.jsonl has project_initialised event with session_id', () => {
323
+ const lines = gf.read('.planning/AUDIT.jsonl').split('\n').filter(Boolean);
324
+ assert.ok(lines.length >= 1, 'Should have at least one audit entry');
325
+ const first = JSON.parse(lines[0]);
326
+ assert.strictEqual(first.event, 'project_initialised');
327
+ assert.ok(first.session_id, 'Should have session_id');
328
+ assert.ok(first.id, 'Should have id');
329
+ assert.ok(first.timestamp, 'Should have timestamp');
330
+ });
331
+
332
+ test('plan-phase creates PLAN files with valid XML structure', () => {
333
+ planPhase(gf, 1);
334
+ const plan = gf.read('.planning/phases/1/PLAN-1-01.md');
335
+ assert.ok(plan, 'PLAN-1-01.md should exist');
336
+ assert.ok(plan.includes('<task type="auto">'), 'Should have task element');
337
+ assert.ok(plan.includes('<n>'), 'Should have task name');
338
+ assert.ok(plan.includes('<persona>'), 'Should specify persona');
339
+ assert.ok(plan.includes('<dependencies>'), 'Should have dependencies');
340
+ assert.ok(plan.includes('<verify>'), 'Should have verify step');
341
+ assert.ok(plan.includes('<done>'), 'Should have definition of done');
342
+ });
343
+
344
+ test('difficulty score file created before plans', () => {
345
+ assert.ok(gf.exists('.planning/phases/1/DIFFICULTY-SCORE-1.md'));
346
+ const score = gf.read('.planning/phases/1/DIFFICULTY-SCORE-1.md');
347
+ assert.ok(score.includes('Composite'), 'Should have composite score');
348
+ assert.ok(score.includes('Challenging'), 'Should have difficulty label');
349
+ });
350
+
351
+ test('dependency graph created and shows wave structure', () => {
352
+ const dep = gf.read('.planning/phases/1/DEPENDENCY-GRAPH-1.md');
353
+ assert.ok(dep, 'Dependency graph should exist');
354
+ assert.ok(dep.includes('Wave 1'), 'Should define Wave 1');
355
+ assert.ok(dep.includes('Wave 2'), 'Should define Wave 2');
356
+ assert.ok(dep.includes('Plan 01'), 'Should reference Plan 01');
357
+ assert.ok(dep.includes('Plan 02'), 'Should reference Plan 02');
358
+ });
359
+
360
+ test('execute task creates SUMMARY with commit SHA', () => {
361
+ executeTask(gf, 1, '01', 'abc1234ef');
362
+ const summary = gf.read('.planning/phases/1/SUMMARY-1-01.md');
363
+ assert.ok(summary, 'SUMMARY-1-01.md should exist');
364
+ assert.ok(summary.includes('Completed ✅'), 'Should show completed status');
365
+ assert.ok(summary.includes('abc1234ef'), 'Should include commit SHA');
366
+ });
367
+
368
+ test('task execution writes task_started and task_completed to AUDIT.jsonl', () => {
369
+ executeTask(gf, 1, '02', 'def5678ab');
370
+ const lines = gf.read('.planning/AUDIT.jsonl').split('\n').filter(Boolean);
371
+ const events = lines.map(l => JSON.parse(l).event);
372
+ assert.ok(events.includes('task_started'), 'Should have task_started event');
373
+ assert.ok(events.includes('task_completed'), 'Should have task_completed event');
374
+ });
375
+
376
+ test('security scan writes SECURITY-REVIEW file', () => {
377
+ runSecurityScan(gf, 1, []);
378
+ assert.ok(gf.exists('.planning/phases/1/SECURITY-REVIEW-1.md'));
379
+ const review = gf.read('.planning/phases/1/SECURITY-REVIEW-1.md');
380
+ assert.ok(review.includes('CLEAN ✅') || review.includes('PASS'), 'Should show passing result');
381
+ });
382
+
383
+ test('verify-phase creates GATE-RESULTS, VERIFICATION, and UAT files', () => {
384
+ verifyPhase(gf, 1);
385
+ assert.ok(gf.exists('.planning/phases/1/GATE-RESULTS-1.md'), 'GATE-RESULTS should exist');
386
+ assert.ok(gf.exists('.planning/phases/1/VERIFICATION-1.md'), 'VERIFICATION should exist');
387
+ assert.ok(gf.exists('.planning/phases/1/UAT-1.md'), 'UAT should exist');
388
+ });
389
+
390
+ test('GATE-RESULTS shows all 5 gates passing', () => {
391
+ const gates = gf.read('.planning/phases/1/GATE-RESULTS-1.md');
392
+ assert.ok(gates.includes('Secret detection'), 'Should have secret detection gate');
393
+ assert.ok(gates.includes('CRITICAL security'), 'Should have CRITICAL findings gate');
394
+ assert.ok(gates.includes('Test suite'), 'Should have test suite gate');
395
+ assert.ok(gates.includes('✅ PASS'), 'Gates should pass');
396
+ assert.ok(gates.includes('ALL BLOCKING GATES PASSED'), 'Should confirm all gates passed');
397
+ });
398
+
399
+ test('VERIFICATION.md references requirements with traceability', () => {
400
+ const v = gf.read('.planning/phases/1/VERIFICATION-1.md');
401
+ assert.ok(v.includes('FR-01'), 'Should reference FR-01');
402
+ assert.ok(v.includes('FR-02'), 'Should reference FR-02');
403
+ assert.ok(v.includes('src/auth/'), 'Should reference source files');
404
+ });
405
+
406
+ // Complete audit log validation
407
+ test('full workflow: all AUDIT.jsonl entries are valid with required fields', () => {
408
+ const lines = gf.read('.planning/AUDIT.jsonl').split('\n').filter(Boolean);
409
+ assert.ok(lines.length >= 6, `Should have >= 6 audit entries, got ${lines.length}`);
410
+
411
+ lines.forEach((line, i) => {
412
+ let entry;
413
+ assert.doesNotThrow(() => { entry = JSON.parse(line); }, `Line ${i+1} is not valid JSON`);
414
+ assert.ok(entry.id, `Line ${i+1}: missing 'id'`);
415
+ assert.ok(entry.timestamp, `Line ${i+1}: missing 'timestamp'`);
416
+ assert.ok(entry.event, `Line ${i+1}: missing 'event'`);
417
+ assert.ok(entry.session_id, `Line ${i+1}: missing 'session_id'`);
418
+ assert.ok(entry.agent, `Line ${i+1}: missing 'agent'`);
419
+ });
420
+ });
421
+
422
+ test('full workflow: AUDIT.jsonl events cover complete lifecycle', () => {
423
+ const lines = gf.read('.planning/AUDIT.jsonl').split('\n').filter(Boolean);
424
+ const events = new Set(lines.map(l => JSON.parse(l).event));
425
+ assert.ok(events.has('project_initialised'), 'Missing: project_initialised');
426
+ assert.ok(events.has('phase_planned'), 'Missing: phase_planned');
427
+ assert.ok(events.has('task_started'), 'Missing: task_started');
428
+ assert.ok(events.has('task_completed'), 'Missing: task_completed');
429
+ assert.ok(events.has('phase_completed'), 'Missing: phase_completed');
430
+ });
431
+
432
+ } finally {
433
+ gf.cleanup();
434
+ }
435
+
436
+ // ── Test 2: Brownfield / map-codebase workflow ─────────────────────────────────
437
+ console.log('\nBrownfield project workflow:');
438
+ const bf = createTestProject();
439
+
440
+ try {
441
+ // Simulate what /mindforge:map-codebase produces
442
+ test('map-codebase creates CONVENTIONS.md with DRAFT status marker', () => {
443
+ bf.write('.mindforge/org/CONVENTIONS.md', `# Coding Conventions — E2E Test Project
444
+ # Source: Inferred from codebase analysis by MindForge
445
+ # Status: DRAFT — confirm with team before treating as authoritative
446
+
447
+ ## IMPORTANT
448
+ These conventions were inferred from code analysis.
449
+ Review each section and mark as [CONFIRMED] or [NEEDS REVIEW].
450
+
451
+ ## Naming conventions [NEEDS REVIEW]
452
+ - Variables: camelCase
453
+ - Files: kebab-case
454
+ - Classes: PascalCase
455
+
456
+ ## Import order [NEEDS REVIEW]
457
+ - Node.js built-ins
458
+ - Third-party libraries
459
+ - Internal modules
460
+ `);
461
+ const content = bf.read('.mindforge/org/CONVENTIONS.md');
462
+ assert.ok(content.includes('DRAFT'), 'Should be marked as DRAFT');
463
+ assert.ok(content.includes('NEEDS REVIEW'), 'Should have review markers');
464
+ });
465
+
466
+ test('map-codebase creates ARCHITECTURE.md with inferred stack', () => {
467
+ bf.write('.planning/ARCHITECTURE.md', `# Architecture — E2E Test Project
468
+ ## MindForge onboarding: Inferred from codebase
469
+ ## Technology stack
470
+ - Runtime: Node.js 20 (inferred from .nvmrc)
471
+ - Framework: Express 4.x (inferred from package.json)
472
+ - Database: PostgreSQL via Prisma (inferred from prisma/schema.prisma)
473
+ ## Quality baseline
474
+ - Tests: Vitest, ~200 test files
475
+ - Linting: ESLint configured
476
+ - CI/CD: GitHub Actions
477
+ `);
478
+ const arch = bf.read('.planning/ARCHITECTURE.md');
479
+ assert.ok(arch, 'ARCHITECTURE.md should exist');
480
+ assert.ok(arch.includes('inferred') || arch.includes('Inferred'), 'Should note inferred content');
481
+ });
482
+
483
+ test('STATE.md from map-codebase shows ready-for-planning status', () => {
484
+ bf.write('.planning/STATE.md', `# Project State
485
+
486
+ ## Status
487
+ Codebase mapped. Ready to plan first phase.
488
+
489
+ ## Current phase
490
+ None — run /mindforge:plan-phase 1 to begin.
491
+
492
+ ## Last action
493
+ /mindforge:map-codebase completed — codebase analysis done.
494
+ `);
495
+ const state = bf.read('.planning/STATE.md');
496
+ assert.ok(state.includes('map'), 'STATE.md should reference map-codebase');
497
+ assert.ok(state.includes('plan'), 'STATE.md should suggest next step');
498
+ });
499
+
500
+ } finally {
501
+ bf.cleanup();
502
+ }
503
+
504
+ // ── Test 3: Multi-developer handoff scenario ──────────────────────────────────
505
+ console.log('\nMulti-developer handoff scenario:');
506
+ const md = createTestProject();
507
+
508
+ try {
509
+ test('per-developer handoffs are distinct and non-conflicting', () => {
510
+ initProject(md);
511
+ const base = JSON.parse(md.read('.planning/HANDOFF.json'));
512
+
513
+ const alice = {
514
+ ...base,
515
+ developer_id: 'alice',
516
+ session_id: 'sess-alice',
517
+ recent_files: ['src/auth/login.ts'],
518
+ };
519
+
520
+ const bob = {
521
+ ...base,
522
+ developer_id: 'bob',
523
+ session_id: 'sess-bob',
524
+ recent_files: ['src/auth/logout.ts'],
525
+ };
526
+
527
+ md.write('.planning/HANDOFF-alice.json', JSON.stringify(alice, null, 2));
528
+ md.write('.planning/HANDOFF-bob.json', JSON.stringify(bob, null, 2));
529
+ md.write('.planning/HANDOFF.json', JSON.stringify({
530
+ ...base,
531
+ active_developers: ['alice', 'bob'],
532
+ }, null, 2));
533
+
534
+ const a = JSON.parse(md.read('.planning/HANDOFF-alice.json'));
535
+ const b = JSON.parse(md.read('.planning/HANDOFF-bob.json'));
536
+ const main = JSON.parse(md.read('.planning/HANDOFF.json'));
537
+
538
+ assert.notStrictEqual(a.session_id, b.session_id, 'Session IDs should be distinct');
539
+ assert.notDeepStrictEqual(a.recent_files, b.recent_files, 'Recent files should differ');
540
+ assert.ok(Array.isArray(main.active_developers), 'active_developers should exist');
541
+ assert.ok(main.active_developers.includes('alice'), 'alice should be in active_developers');
542
+ assert.ok(main.active_developers.includes('bob'), 'bob should be in active_developers');
543
+ });
544
+ } finally {
545
+ md.cleanup();
546
+ }
547
+
548
+ // ── Test 4: Context compaction scenario ───────────────────────────────────────
549
+ console.log('\nContext compaction scenario:');
550
+ const cc = createTestProject();
551
+
552
+ try {
553
+ test('Level 2 compaction adds decisions_made and implicit_knowledge', () => {
554
+ initProject(cc);
555
+ const handoff = JSON.parse(cc.read('.planning/HANDOFF.json'));
556
+ handoff.decisions_made = ['Adopted JWT auth for v1'];
557
+ handoff.implicit_knowledge = ['Token revocation uses Redis blocklist'];
558
+ cc.write('.planning/HANDOFF.json', JSON.stringify(handoff, null, 2));
559
+
560
+ const updated = JSON.parse(cc.read('.planning/HANDOFF.json'));
561
+ assert.ok(Array.isArray(updated.decisions_made), 'decisions_made should be array');
562
+ assert.ok(Array.isArray(updated.implicit_knowledge), 'implicit_knowledge should be array');
563
+ assert.ok(updated.decisions_made.length >= 1, 'decisions_made should be populated');
564
+ assert.ok(updated.implicit_knowledge.length >= 1, 'implicit_knowledge should be populated');
565
+ });
566
+ } finally {
567
+ cc.cleanup();
568
+ }
569
+
570
+ // ── Test 5: Security gate scenarios ───────────────────────────────────────────
571
+ console.log('\nSecurity gate scenarios:');
572
+ const sg = createTestProject();
573
+
574
+ try {
575
+ test('CRITICAL security finding in review blocks phase completion indicator', () => {
576
+ initProject(sg);
577
+ planPhase(sg, 1);
578
+ executeTask(sg, 1, '01', 'abc1234');
579
+
580
+ // Run security scan with a CRITICAL finding
581
+ runSecurityScan(sg, 1, [{
582
+ severity: 'CRITICAL',
583
+ description: 'SQL injection via unsanitised user input',
584
+ file: 'src/db/users.ts',
585
+ line: 47,
586
+ remediation: 'Use parameterised queries: db.query($1, [id])',
587
+ }]);
588
+
589
+ const review = sg.read('.planning/phases/1/SECURITY-REVIEW-1.md');
590
+ assert.ok(review.includes('CRITICAL'), 'Should show CRITICAL finding');
591
+ assert.ok(review.includes('BLOCKED') || review.includes('0 CRITICAL') === false, 'Should indicate blocked state');
592
+ });
593
+
594
+ test('AUDIT.jsonl captures security findings with correct schema', () => {
595
+ const lines = sg.read('.planning/AUDIT.jsonl').split('\n').filter(Boolean);
596
+ const secScan = lines.map(l => JSON.parse(l)).find(e => e.event === 'security_scan_completed');
597
+ assert.ok(secScan, 'Should have security_scan_completed audit entry');
598
+ assert.strictEqual(secScan.critical, 1, 'Should record 1 critical finding');
599
+ assert.ok(secScan.session_id, 'Security scan audit entry should have session_id');
600
+ });
601
+
602
+ } finally {
603
+ sg.cleanup();
604
+ }
605
+
606
+ // ── Results ─────────────────────────────────────────────────────────────────────
607
+ console.log(`\n${'─'.repeat(55)}`);
608
+ console.log(`Results: ${passed} passed, ${failed} failed`);
609
+ if (cleanupFailures.length > 0) {
610
+ console.warn(`\n⚠️ ${cleanupFailures.length} test directories were not cleaned up:`);
611
+ cleanupFailures.forEach(p => console.warn(` - ${p}`));
612
+ }
613
+ if (failed > 0) {
614
+ console.error(`\n❌ ${failed} test(s) failed.\n`);
615
+ process.exit(1);
616
+ } else {
617
+ console.log(`\n✅ All E2E tests passed.\n`);
618
+ }