# Story 16.5: Fix Config Lost on Update (Bug)

Status: review

<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->

## Story

As a **user with a multi-repo layout configured**,
I want my repo layout configuration to be preserved when I update ma-agents,
So that I don't silently lose my multi-repo paths every time I add a skill or update agents.

## Bug Description

`collectRepoLayout()` is called unconditionally at [cli.js:595](bin/cli.js#L595) during every install/update run. Unlike skill and agent selections — which are pre-populated during updates — the repo layout prompt starts blank every time. If the user accepts defaults (or runs `--yes` without env vars), the existing multi-repo config in `config.yaml` and `project-layout.yaml` is overwritten with single-repo defaults.

**Reproduction steps:**
1. Run `npx ma-agents` and configure multi-repo layout (e.g., knowledgebase at `/ext/kb`)
2. Run `npx ma-agents` again to add a new skill
3. At the repo layout prompt, accept defaults (or press Enter)
4. Config.yaml now has `knowledgebase_path: "."` — previous config lost

**Root cause:** No `readExistingLayout()` function exists. The update path never reads the current `project-layout.yaml` or `config.yaml` to pre-populate the prompts.

## Acceptance Criteria

1. **Given** an existing installation with multi-repo layout configured in `_bmad-output/project-layout.yaml`, **When** the user runs `ma-agents` again and selects "Update", **Then** the repo layout prompts are pre-populated with the existing configuration (mode, path, gitUrl)
2. **Given** an existing installation with single-repo layout (no `project-layout.yaml`), **When** the user runs `ma-agents` again, **Then** the repo layout defaults to single-repo as before (no behavioral change)
3. **Given** an update with `--yes` flag and no env vars, **When** `project-layout.yaml` exists with multi-repo paths, **Then** the existing layout is preserved (read from file) instead of defaulting to single-repo
4. **Given** an update with `--yes` flag and env vars set, **When** `project-layout.yaml` also exists, **Then** the env vars take precedence over the file (explicit override wins)
5. **Given** a fresh install (no existing `project-layout.yaml`), **When** the wizard runs, **Then** behavior is identical to current implementation (no regression)
6. **Given** an existing multi-repo layout, **When** the user explicitly changes layout during update (selects different mode/path), **Then** the new configuration replaces the old one as expected

## Tasks / Subtasks

- [x] Task 1: Implement `readExistingLayout()` function in `bin/cli.js`
  - [x] 1.1 Read `_bmad-output/project-layout.yaml` if it exists; parse YAML fields (mode, path, gitUrl for each concern)
  - [x] 1.2 If file doesn't exist, check `_bmad/bmm/config.yaml` for `knowledgebase_path` and `sprint_management_path` fields as fallback
  - [x] 1.3 Return layout object matching `collectRepoLayout()` return shape, or `null` if no existing config found
  - [x] 1.4 Handle parse errors gracefully — return `null` on corruption (don't crash the installer)

- [x] Task 2: Modify `collectRepoLayout()` to accept and use existing layout
  - [x] 2.1 Add `existingLayout` parameter: `collectRepoLayout(flags, existingLayout = null)`
  - [x] 2.2 In `--yes` mode: if env vars not set AND `existingLayout` is not null, return `existingLayout` (preserve existing config)
  - [x] 2.3 In `--yes` mode: env vars still take precedence over existing layout (AC #4)
  - [x] 2.4 In interactive mode: use `existingLayout` to set `initial` values on prompts — pre-select the current mode for each concern
  - [x] 2.5 When user selects same mode as existing, pre-fill path/URL from existing config

- [x] Task 3: Wire into `installWizard()`
  - [x] 3.1 Before calling `collectRepoLayout()`, call `readExistingLayout()` when `isUpdate` is true
  - [x] 3.2 Pass existing layout to `collectRepoLayout(flags, existingLayout)`

- [x] Task 4: Write unit tests
  - [x] 4.1 Test `readExistingLayout()` with valid `project-layout.yaml` returns correct layout object
  - [x] 4.2 Test `readExistingLayout()` with missing file returns null
  - [x] 4.3 Test `readExistingLayout()` with corrupt YAML returns null (no crash)
  - [x] 4.4 Test `--yes` mode preserves existing layout when no env vars set
  - [x] 4.5 Test `--yes` mode with env vars overrides existing layout
  - [x] 4.6 Test fresh install (no existing layout) behaves identically to current code

## Dev Notes

### Key Files

- `bin/cli.js` — `collectRepoLayout()` (~line 370), `installWizard()` (~line 595)
- `_bmad-output/project-layout.yaml` — existing config file written by Story 16.2

### YAML Parsing

The project does not use a YAML library. `project-layout.yaml` is simple flat/nested YAML generated by `writeProjectLayoutYaml()`. Parse with regex or line-by-line — match the existing pattern in `writeConfigField()`. Do NOT add a YAML dependency for this.

### Backward Compatibility

- Fresh installs must behave identically (no existing layout = current behavior)
- `readExistingLayout()` returning `null` means "no existing config" — fall through to current flow
- Export `readExistingLayout` for testability

### References

- [Source: bin/cli.js — collectRepoLayout() at line 370]
- [Source: bin/cli.js — installWizard() at line 595]
- [Source: Adversarial Review Finding #1 — config destroyed on update]

## Dev Agent Record

### Implementation Plan
- Added `readExistingLayout()` before `collectRepoLayout()` in the update path
- `readExistingLayout()` reads `project-layout.yaml` first (authoritative), falls back to `config.yaml` path fields
- Modified `collectRepoLayout()` to accept `existingLayout` parameter for pre-population
- `--yes` mode: env vars > existing layout > defaults (priority chain)
- Interactive mode: pre-selects existing mode in prompts via `initial` index

### Completion Notes
- All 4 tasks implemented and verified with 13 dedicated tests
- Full regression suite passes (all existing tests unaffected)
- `readExistingLayout()` exported for testability
- No new dependencies added — regex-based YAML parsing matches existing project pattern
- Round-trip test confirms `writeProjectLayoutYaml()` → `readExistingLayout()` works correctly
- Backward compatibility verified: fresh installs with no existing layout behave identically

## File List

- `bin/cli.js` — Added `readExistingLayout()`, modified `collectRepoLayout()` signature and `--yes` logic, updated interactive prompt pre-selection, wired into `installWizard()`, updated exports
- `test/config-lost-on-update.test.js` — New: 13 unit tests covering readExistingLayout, collectRepoLayout with existingLayout, round-trip
- `_bmad-output/implementation-artifacts/sprint-status.yaml` — Updated 16-5 status: ready-for-dev → in-progress → review
- `_bmad-output/implementation-artifacts/16-5-fix-config-lost-on-update.md` — Updated task checkboxes, status, dev agent record

## Change Log

- 2026-03-28: Implemented bug fix for config lost on update — `readExistingLayout()` reads existing multi-repo layout from `project-layout.yaml` / `config.yaml` and pre-populates `collectRepoLayout()` during updates. 13 tests added.
