From 5bfe295eb274f53183b581352182465ba21efcf3 Mon Sep 17 00:00:00 2001 From: Egor Merkushev Date: Thu, 19 Feb 2026 23:16:59 +0300 Subject: [PATCH 1/7] Branch for FU-P13-T13-FU-1: ensure rollback stop events are set From f5f59cbcc5e1933f5d0ac3eb7e3a8e0c224be3e0 Mon Sep 17 00:00:00 2001 From: Egor Merkushev Date: Thu, 19 Feb 2026 23:17:24 +0300 Subject: [PATCH 2/7] Select task FU-P13-T13-FU-1: Set _stopped_event and _stop_event in _rollback_startup for defensive consistency --- SPECS/INPROGRESS/next.md | 19 +++++++++++++------ SPECS/Workplan.md | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/SPECS/INPROGRESS/next.md b/SPECS/INPROGRESS/next.md index e1d3a7c5..e9f5ccfe 100644 --- a/SPECS/INPROGRESS/next.md +++ b/SPECS/INPROGRESS/next.md @@ -1,10 +1,17 @@ -# No Active Task +# Next Task: FU-P13-T13-FU-1 — Set _stopped_event and _stop_event in _rollback_startup for defensive consistency -## Recently Archived +**Priority:** P3 +**Phase:** Phase 13 — Persistent Broker & Shared Xcode Session +**Effort:** 30-60m +**Dependencies:** FU-P13-T13 (✅) +**Status:** Selected -- **FU-P13-T15** — Restore broker same-UID client acceptance when peer credential APIs are unavailable (2026-02-19, PASS) -- **FU-P13-T14** — Complete interactive Xcode prompt verification and close P13-T5 (2026-02-19, FAIL) +## Description -## Suggested Next Tasks +After `_rollback_startup()` sets broker state to `STOPPED`, also set +`self._stopped_event` and `self._stop_event` so event flags are consistent with +the STOPPED contract in future call paths. -- **FU-P13-T13-FU-1** — Set _stopped_event and _stop_event in _rollback_startup for defensive consistency (P3) +## Next Step + +Run the PLAN command to generate the implementation-ready PRD. diff --git a/SPECS/Workplan.md b/SPECS/Workplan.md index b53dc118..340c62ec 100644 --- a/SPECS/Workplan.md +++ b/SPECS/Workplan.md @@ -2259,7 +2259,7 @@ Phase 9 Follow-up Backlog --- -#### ⬜️ FU-P13-T13-FU-1: Set _stopped_event and _stop_event in _rollback_startup for defensive consistency +#### 🔄 FU-P13-T13-FU-1: Set _stopped_event and _stop_event in _rollback_startup for defensive consistency **INPROGRESS** - **Description:** After `_rollback_startup()` sets state to STOPPED, also call `self._stopped_event.set()` and `self._stop_event.set()` so all event states are consistent with the STOPPED contract. These paths are currently unreachable by callers but the defensive fix ensures correctness if future callers are added. - **Priority:** P3 (Low — optional defensibility improvement) - **Dependencies:** FU-P13-T13 (✅) From 2b5544939566e5baed4f6902f3dfcd81a1dc3c43 Mon Sep 17 00:00:00 2001 From: Egor Merkushev Date: Thu, 19 Feb 2026 23:18:06 +0300 Subject: [PATCH 3/7] Plan task FU-P13-T13-FU-1: Set _stopped_event and _stop_event in _rollback_startup for defensive consistency --- ...lback_startup_for_defensive_consistency.md | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 SPECS/INPROGRESS/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency.md diff --git a/SPECS/INPROGRESS/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency.md b/SPECS/INPROGRESS/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency.md new file mode 100644 index 00000000..ccb51fa6 --- /dev/null +++ b/SPECS/INPROGRESS/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency.md @@ -0,0 +1,57 @@ +# PRD: FU-P13-T13-FU-1 — Set _stopped_event and _stop_event in _rollback_startup for defensive consistency + +**Status:** INPROGRESS +**Priority:** P3 +**Phase:** Phase 13 — Persistent Broker & Shared Xcode Session +**Dependencies:** FU-P13-T13 (✅) + +--- + +## 1. Objective + +Ensure `_rollback_startup()` leaves event flags fully consistent with STOPPED +state by setting both `_stop_event` and `_stopped_event` during rollback. + +--- + +## 2. Background + +`_rollback_startup()` currently: +- Cancels read task +- Terminates upstream +- Cleans files +- Sets `self._state = BrokerState.STOPPED` + +It does not explicitly set `_stop_event` / `_stopped_event` in this path. While +current call paths do not await these events after startup rollback, setting them +is a defensive consistency improvement and prevents future state/event mismatch. + +--- + +## 3. Design + +1. Update `BrokerDaemon._rollback_startup()` to call: + - `self._stop_event.set()` + - `self._stopped_event.set()` +2. Keep existing rollback sequence and error behavior unchanged. +3. Add regression test asserting both events are set after a startup failure + that triggers rollback. + +--- + +## 4. Files To Change + +| File | Change | +|------|--------| +| `src/mcpbridge_wrapper/broker/daemon.py` | Set stop/stopped events in `_rollback_startup()` | +| `tests/unit/test_broker_daemon.py` | Add assertion coverage for event state after rollback | +| `SPECS/INPROGRESS/FU-P13-T13-FU-1_Validation_Report.md` | Record validation and quality-gate outcomes | + +--- + +## 5. Acceptance Criteria + +- [ ] `_stopped_event.set()` called in `_rollback_startup()` +- [ ] `_stop_event.set()` called in `_rollback_startup()` +- [ ] Tests verify event states are set after a failed startup +- [ ] Quality gates are executed and recorded From 0323a4eb63f05c4aef2b6b84ce8de032e39108ff Mon Sep 17 00:00:00 2001 From: Egor Merkushev Date: Thu, 19 Feb 2026 23:21:16 +0300 Subject: [PATCH 4/7] Implement FU-P13-T13-FU-1: set rollback stop events and add regression test --- .../FU-P13-T13-FU-1_Validation_Report.md | 52 +++++++++++++++++++ src/mcpbridge_wrapper/broker/daemon.py | 3 ++ tests/unit/test_broker_daemon.py | 22 ++++++++ 3 files changed, 77 insertions(+) create mode 100644 SPECS/INPROGRESS/FU-P13-T13-FU-1_Validation_Report.md diff --git a/SPECS/INPROGRESS/FU-P13-T13-FU-1_Validation_Report.md b/SPECS/INPROGRESS/FU-P13-T13-FU-1_Validation_Report.md new file mode 100644 index 00000000..7819e247 --- /dev/null +++ b/SPECS/INPROGRESS/FU-P13-T13-FU-1_Validation_Report.md @@ -0,0 +1,52 @@ +# Validation Report: FU-P13-T13-FU-1 — Set _stopped_event and _stop_event in _rollback_startup for defensive consistency + +**Date:** 2026-02-19 +**Verdict:** PASS + +--- + +## Acceptance Criteria + +| # | Criterion | Status | +|---|-----------|--------| +| 1 | `_stopped_event.set()` is called in `_rollback_startup()` | ✅ PASS | +| 2 | `_stop_event.set()` is called in `_rollback_startup()` | ✅ PASS | +| 3 | Tests verify event states are set after startup rollback | ✅ PASS | +| 4 | Quality gates are executed and documented | ✅ PASS | + +--- + +## Evidence + +### Implementation evidence + +`BrokerDaemon._rollback_startup()` now sets both stop events after transitioning to `BrokerState.STOPPED`: + +- `self._stop_event.set()` +- `self._stopped_event.set()` + +### Test evidence + +Added unit test: + +- `tests/unit/test_broker_daemon.py::TestStartupRollback::test_transport_start_failure_sets_stop_events` + +The test verifies that when startup fails and rollback runs, both event flags are set and daemon state is `STOPPED`. + +--- + +## Quality Gates + +| Gate | Result | Notes | +|------|--------|-------| +| `TMPDIR=/tmp pytest` | ✅ PASS | 624 passed, 5 skipped. | +| `ruff check src/` | ✅ PASS | All checks passed. | +| `mypy src/` | ✅ PASS | Success: no issues found in 18 source files. | +| `TMPDIR=/tmp pytest --cov` | ✅ PASS | 624 passed, 5 skipped; total coverage 91.70% (>=90%). | + +--- + +## Changed Files + +- `src/mcpbridge_wrapper/broker/daemon.py` +- `tests/unit/test_broker_daemon.py` diff --git a/src/mcpbridge_wrapper/broker/daemon.py b/src/mcpbridge_wrapper/broker/daemon.py index 5f5e6cdd..3bd553cc 100644 --- a/src/mcpbridge_wrapper/broker/daemon.py +++ b/src/mcpbridge_wrapper/broker/daemon.py @@ -261,6 +261,9 @@ async def _rollback_startup(self) -> None: # Remove stale files and mark daemon as stopped self._cleanup_files() self._state = BrokerState.STOPPED + # Keep event flags consistent with STOPPED state for future callers. + self._stop_event.set() + self._stopped_event.set() logger.info("Startup rollback complete — broker STOPPED.") def _check_and_clear_stale_lock(self) -> None: diff --git a/tests/unit/test_broker_daemon.py b/tests/unit/test_broker_daemon.py index 6f783f7e..a3642b45 100644 --- a/tests/unit/test_broker_daemon.py +++ b/tests/unit/test_broker_daemon.py @@ -936,3 +936,25 @@ async def test_pid_write_failure_terminates_upstream(self, tmp_path: Path) -> No proc.terminate.assert_called_once() assert daemon.state == BrokerState.STOPPED + + @pytest.mark.asyncio + async def test_transport_start_failure_sets_stop_events(self, tmp_path: Path) -> None: + """Rollback sets both stop events to match STOPPED state.""" + cfg = _make_config(tmp_path) + transport = MagicMock() + transport.start = AsyncMock(side_effect=OSError("addr in use")) + transport.stop = AsyncMock() + daemon = BrokerDaemon(cfg, transport=transport) + + proc = _make_mock_process() + proc.terminate = MagicMock() + + with patch( + "mcpbridge_wrapper.broker.daemon.asyncio.create_subprocess_exec", + new=AsyncMock(return_value=proc), + ), pytest.raises(OSError): + await daemon.start() + + assert daemon.state == BrokerState.STOPPED + assert daemon._stop_event.is_set() + assert daemon._stopped_event.is_set() From df0deb21fce8237bd5b44b2642fe618d121e538a Mon Sep 17 00:00:00 2001 From: Egor Merkushev Date: Thu, 19 Feb 2026 23:23:00 +0300 Subject: [PATCH 5/7] Archive task FU-P13-T13-FU-1: Set _stopped_event and _stop_event in _rollback_startup for defensive consistency (PASS) --- ...rollback_startup_for_defensive_consistency.md | 4 ++++ .../FU-P13-T13-FU-1_Validation_Report.md | 0 SPECS/ARCHIVE/INDEX.md | 4 +++- SPECS/INPROGRESS/next.md | 16 +++++----------- SPECS/Workplan.md | 8 ++++---- 5 files changed, 16 insertions(+), 16 deletions(-) rename SPECS/{INPROGRESS => ARCHIVE/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency}/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency.md (97%) rename SPECS/{INPROGRESS => ARCHIVE/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency}/FU-P13-T13-FU-1_Validation_Report.md (100%) diff --git a/SPECS/INPROGRESS/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency.md b/SPECS/ARCHIVE/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency.md similarity index 97% rename from SPECS/INPROGRESS/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency.md rename to SPECS/ARCHIVE/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency.md index ccb51fa6..b1273b95 100644 --- a/SPECS/INPROGRESS/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency.md +++ b/SPECS/ARCHIVE/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency.md @@ -55,3 +55,7 @@ is a defensive consistency improvement and prevents future state/event mismatch. - [ ] `_stop_event.set()` called in `_rollback_startup()` - [ ] Tests verify event states are set after a failed startup - [ ] Quality gates are executed and recorded + +--- +**Archived:** 2026-02-19 +**Verdict:** PASS diff --git a/SPECS/INPROGRESS/FU-P13-T13-FU-1_Validation_Report.md b/SPECS/ARCHIVE/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency/FU-P13-T13-FU-1_Validation_Report.md similarity index 100% rename from SPECS/INPROGRESS/FU-P13-T13-FU-1_Validation_Report.md rename to SPECS/ARCHIVE/FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency/FU-P13-T13-FU-1_Validation_Report.md diff --git a/SPECS/ARCHIVE/INDEX.md b/SPECS/ARCHIVE/INDEX.md index 73c6e228..fb0f2b5c 100644 --- a/SPECS/ARCHIVE/INDEX.md +++ b/SPECS/ARCHIVE/INDEX.md @@ -1,6 +1,6 @@ # mcpbridge-wrapper Tasks Archive -**Last Updated:** 2026-02-19 (FU-P13-T15_Restore_broker_same-UID_client_acceptance_when_peer_credential_APIs_are_unavailable) +**Last Updated:** 2026-02-19 (FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency) ## Archived Tasks @@ -129,6 +129,7 @@ | FU-P13-T13 | [FU-P13-T13_Make_broker_startup_transactional_when_transport_bind_start_fails/](FU-P13-T13_Make_broker_startup_transactional_when_transport_bind_start_fails/) | 2026-02-19 | PASS | | FU-P13-T14 | [FU-P13-T14_Complete_interactive_Xcode_prompt_verification_and_close_P13-T5/](FU-P13-T14_Complete_interactive_Xcode_prompt_verification_and_close_P13-T5/) | 2026-02-19 | FAIL | | FU-P13-T15 | [FU-P13-T15_Restore_broker_same-UID_client_acceptance_when_peer_credential_APIs_are_unavailable/](FU-P13-T15_Restore_broker_same-UID_client_acceptance_when_peer_credential_APIs_are_unavailable/) | 2026-02-19 | PASS | +| FU-P13-T13-FU-1 | [FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency/](FU-P13-T13-FU-1_Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency/) | 2026-02-19 | PASS | ## Historical Artifacts @@ -401,3 +402,4 @@ | 2026-02-19 | FU-P13-T14 | Archived REVIEW_FU-P13-T14_prompt_validation_closeout report | | 2026-02-19 | FU-P13-T15 | Archived Restore_broker_same-UID_client_acceptance_when_peer_credential_APIs_are_unavailable (PASS) | | 2026-02-19 | FU-P13-T15 | Archived REVIEW_FU-P13-T15_peer_credential_fallback report | +| 2026-02-19 | FU-P13-T13-FU-1 | Archived Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency (PASS) | diff --git a/SPECS/INPROGRESS/next.md b/SPECS/INPROGRESS/next.md index e9f5ccfe..306e9ac6 100644 --- a/SPECS/INPROGRESS/next.md +++ b/SPECS/INPROGRESS/next.md @@ -1,17 +1,11 @@ -# Next Task: FU-P13-T13-FU-1 — Set _stopped_event and _stop_event in _rollback_startup for defensive consistency +# Next Task: None — All Tasks Completed -**Priority:** P3 -**Phase:** Phase 13 — Persistent Broker & Shared Xcode Session -**Effort:** 30-60m -**Dependencies:** FU-P13-T13 (✅) -**Status:** Selected +**Status:** Waiting for new tasks -## Description +## Recently Archived -After `_rollback_startup()` sets broker state to `STOPPED`, also set -`self._stopped_event` and `self._stop_event` so event flags are consistent with -the STOPPED contract in future call paths. +- `FU-P13-T13-FU-1` — Set _stopped_event and _stop_event in _rollback_startup for defensive consistency (2026-02-19, PASS) ## Next Step -Run the PLAN command to generate the implementation-ready PRD. +Add or prioritize follow-up work in `SPECS/Workplan.md`, then run SELECT. diff --git a/SPECS/Workplan.md b/SPECS/Workplan.md index 340c62ec..e9bb0c20 100644 --- a/SPECS/Workplan.md +++ b/SPECS/Workplan.md @@ -2259,7 +2259,7 @@ Phase 9 Follow-up Backlog --- -#### 🔄 FU-P13-T13-FU-1: Set _stopped_event and _stop_event in _rollback_startup for defensive consistency **INPROGRESS** +#### ✅ FU-P13-T13-FU-1: Set _stopped_event and _stop_event in _rollback_startup for defensive consistency — Completed (2026-02-19, PASS) - **Description:** After `_rollback_startup()` sets state to STOPPED, also call `self._stopped_event.set()` and `self._stop_event.set()` so all event states are consistent with the STOPPED contract. These paths are currently unreachable by callers but the defensive fix ensures correctness if future callers are added. - **Priority:** P3 (Low — optional defensibility improvement) - **Dependencies:** FU-P13-T13 (✅) @@ -2268,9 +2268,9 @@ Phase 9 Follow-up Backlog - Updated `src/mcpbridge_wrapper/broker/daemon.py` `_rollback_startup()` method - Updated tests asserting event state after rollback - **Acceptance Criteria:** - - [ ] `_stopped_event.set()` called in `_rollback_startup()` - - [ ] `_stop_event.set()` called in `_rollback_startup()` - - [ ] Tests verify event states are set after a failed startup + - [x] `_stopped_event.set()` called in `_rollback_startup()` + - [x] `_stop_event.set()` called in `_rollback_startup()` + - [x] Tests verify event states are set after a failed startup --- From d7e5c41ba04714da64f50868cf5290acce7716b8 Mon Sep 17 00:00:00 2001 From: Egor Merkushev Date: Thu, 19 Feb 2026 23:23:31 +0300 Subject: [PATCH 6/7] Review FU-P13-T13-FU-1: rollback event consistency --- ...P13-T13-FU-1_rollback_event_consistency.md | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 SPECS/INPROGRESS/REVIEW_FU-P13-T13-FU-1_rollback_event_consistency.md diff --git a/SPECS/INPROGRESS/REVIEW_FU-P13-T13-FU-1_rollback_event_consistency.md b/SPECS/INPROGRESS/REVIEW_FU-P13-T13-FU-1_rollback_event_consistency.md new file mode 100644 index 00000000..109249fa --- /dev/null +++ b/SPECS/INPROGRESS/REVIEW_FU-P13-T13-FU-1_rollback_event_consistency.md @@ -0,0 +1,34 @@ +## REVIEW REPORT — FU-P13-T13-FU-1 rollback event consistency + +**Scope:** `origin/main..HEAD` +**Files:** 7 + +### Summary Verdict +- [x] Approve +- [ ] Approve with comments +- [ ] Request changes +- [ ] Block + +### Critical Issues + +None. + +### Secondary Issues + +None. + +### Architectural Notes + +- `_rollback_startup()` now aligns state and signaling contracts by setting both `_stop_event` and `_stopped_event` when rollback transitions the daemon to `STOPPED`. +- The added regression test directly exercises transport startup failure and validates defensive event consistency. + +### Tests + +- `TMPDIR=/tmp pytest` → 624 passed, 5 skipped +- `ruff check src/` → pass +- `mypy src/` → pass +- `TMPDIR=/tmp pytest --cov` → 91.70% total coverage (>=90%) + +### Next Steps + +- FOLLOW-UP skipped: no actionable review findings. From fd5b739d84bdefee22bf8d2e903abfee1faae628 Mon Sep 17 00:00:00 2001 From: Egor Merkushev Date: Thu, 19 Feb 2026 23:24:00 +0300 Subject: [PATCH 7/7] Archive REVIEW_FU-P13-T13-FU-1_rollback_event_consistency report --- SPECS/ARCHIVE/INDEX.md | 2 ++ .../REVIEW_FU-P13-T13-FU-1_rollback_event_consistency.md | 0 2 files changed, 2 insertions(+) rename SPECS/{INPROGRESS => ARCHIVE/_Historical}/REVIEW_FU-P13-T13-FU-1_rollback_event_consistency.md (100%) diff --git a/SPECS/ARCHIVE/INDEX.md b/SPECS/ARCHIVE/INDEX.md index fb0f2b5c..fdd1c7df 100644 --- a/SPECS/ARCHIVE/INDEX.md +++ b/SPECS/ARCHIVE/INDEX.md @@ -224,6 +224,7 @@ | [REVIEW_FU-P13-T13_transactional_startup.md](_Historical/REVIEW_FU-P13-T13_transactional_startup.md) | Review report for FU-P13-T13 | | [REVIEW_FU-P13-T14_prompt_validation_closeout.md](_Historical/REVIEW_FU-P13-T14_prompt_validation_closeout.md) | Review report for FU-P13-T14 | | [REVIEW_FU-P13-T15_peer_credential_fallback.md](_Historical/REVIEW_FU-P13-T15_peer_credential_fallback.md) | Review report for FU-P13-T15 | +| [REVIEW_FU-P13-T13-FU-1_rollback_event_consistency.md](_Historical/REVIEW_FU-P13-T13-FU-1_rollback_event_consistency.md) | Review report for FU-P13-T13-FU-1 | ## Archive Log @@ -403,3 +404,4 @@ | 2026-02-19 | FU-P13-T15 | Archived Restore_broker_same-UID_client_acceptance_when_peer_credential_APIs_are_unavailable (PASS) | | 2026-02-19 | FU-P13-T15 | Archived REVIEW_FU-P13-T15_peer_credential_fallback report | | 2026-02-19 | FU-P13-T13-FU-1 | Archived Set__stopped_event_and__stop_event_in__rollback_startup_for_defensive_consistency (PASS) | +| 2026-02-19 | FU-P13-T13-FU-1 | Archived REVIEW_FU-P13-T13-FU-1_rollback_event_consistency report | diff --git a/SPECS/INPROGRESS/REVIEW_FU-P13-T13-FU-1_rollback_event_consistency.md b/SPECS/ARCHIVE/_Historical/REVIEW_FU-P13-T13-FU-1_rollback_event_consistency.md similarity index 100% rename from SPECS/INPROGRESS/REVIEW_FU-P13-T13-FU-1_rollback_event_consistency.md rename to SPECS/ARCHIVE/_Historical/REVIEW_FU-P13-T13-FU-1_rollback_event_consistency.md