* Arm the loop with a list of requirements. * Each entry is a plain-English description of behaviour to implement. * Does not start a cycle — call beginCycle() or let the governor auto-start. * * @param {string[]} requirements * @returns {{ ok: boolean, message: string, requirements:
(requirements)
| 127 | * @returns {{ ok: boolean, message: string, requirements: object[] }} |
| 128 | */ |
| 129 | initRequirements(requirements) { |
| 130 | if (this.disabled) return { ok: true, message: 'TDD gating disabled.', requirements: [] }; |
| 131 | if (!Array.isArray(requirements) || requirements.length === 0) { |
| 132 | return { ok: false, message: 'initRequirements: pass a non-empty array of requirement strings.' }; |
| 133 | } |
| 134 | |
| 135 | this._requirements = requirements |
| 136 | .map((text, i) => String(text || '').trim()) |
| 137 | .filter(Boolean) |
| 138 | .map((text, i) => ({ id: `r${String(i + 1).padStart(2, '0')}`, text, status: REQ_STATUS.PENDING })); |
| 139 | |
| 140 | if (this._requirements.length === 0) { |
| 141 | return { ok: false, message: 'initRequirements: all requirement strings were empty.' }; |
| 142 | } |
| 143 | |
| 144 | this._loopActive = true; |
| 145 | this._regressionClean = false; |
| 146 | // Reset any in-flight cycle |
| 147 | this._phase = PHASES.IDLE; |
| 148 | this._targetTest = null; |
| 149 | this._redConfirmed = false; |
| 150 | this._save(); |
| 151 | |
| 152 | const lines = this._requirements.map(r => ` ○ ${r.id}: ${r.text}`).join('\n'); |
| 153 | return { |
| 154 | ok: true, |
| 155 | message: `TDD loop initialised with ${this._requirements.length} requirement(s):\n${lines}\n\nNext: write a failing test for "${this._requirements[0].text}", then call tdd_begin_cycle.`, |
| 156 | requirements: this._requirements, |
| 157 | }; |
| 158 | } |
| 159 | |
| 160 | /** |
| 161 | * Mark a requirement as complete (used internally after a cycle reaches green). |