Skip to content
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ A Python wrapper (`xcodemcpwrapper`) that intercepts responses from `xcrun mcpbr

### Metrics

- **Test Coverage:** 92.19%
- **Test Coverage:** 91.62%
- **Performance:** <0.01ms overhead per transformation (0.0023ms avg)
- **Memory:** <10MB footprint
- **Lines of Code:** ~400 Python + 2000+ lines documentation
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<!-- version-badge:end -->
[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Coverage](https://img.shields.io/badge/coverage-90.91%25-brightgreen.svg)](./SPECS/ARCHIVE/P5-T14_Code_Coverage/)
[![Coverage](https://img.shields.io/badge/coverage-91.62%25-brightgreen.svg)](./SPECS/ARCHIVE/P5-T14_Code_Coverage/)
<!-- coverage-sync: keep README and DocC coverage metrics aligned -->
[![MCP Registry](https://img.shields.io/badge/MCP%20Registry-io.github.SoundBlaster%2Fxcode--mcpbridge--wrapper-blue)](https://registry.modelcontextprotocol.io)

Expand Down Expand Up @@ -664,7 +664,7 @@ make test && make lint && make typecheck

- **Overhead:** <0.01ms per transformation
- **Memory:** <10MB footprint
- **Coverage:** 90.91% test coverage
- **Coverage:** 91.62% test coverage

## License

Expand Down
6 changes: 5 additions & 1 deletion SPECS/ARCHIVE/INDEX.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# mcpbridge-wrapper Tasks Archive

**Last Updated:** 2026-03-07 (P7-T2 review archived)
**Last Updated:** 2026-03-07 (P7-T3 review archived)

## Archived Tasks

| Task ID | Folder | Archived | Verdict |
|---------|--------|----------|---------|
| P7-T3 | [P7-T3_Auto-recover_or_guide_on_dashboard_port_ownership_conflicts/](P7-T3_Auto-recover_or_guide_on_dashboard_port_ownership_conflicts/) | 2026-03-07 | PASS |
| P7-T2 | [P7-T2_Implement_a_broker_doctor_command_for_cross-black-box_diagnostics/](P7-T2_Implement_a_broker_doctor_command_for_cross-black-box_diagnostics/) | 2026-03-07 | PASS |
| P7-T1 | [P7-T1_Add_one-command_broker_host_startup_with_attached_frontend/](P7-T1_Add_one-command_broker_host_startup_with_attached_frontend/) | 2026-03-07 | PASS |
| P6-T3 | [P6-T3_Document_the_explicit_dedicated-host_frontend_workflow/](P6-T3_Document_the_explicit_dedicated-host_frontend_workflow/) | 2026-03-07 | PASS |
Expand Down Expand Up @@ -198,6 +199,7 @@

| File | Description |
|------|-------------|
| [REVIEW_dashboard_port_ownership_conflicts.md](_Historical/REVIEW_dashboard_port_ownership_conflicts.md) | Review report for P7-T3 |
| [REVIEW_broker_doctor_diagnostics.md](_Historical/REVIEW_broker_doctor_diagnostics.md) | Review report for P7-T2 |
| [REVIEW_broker_console_startup.md](_Historical/REVIEW_broker_console_startup.md) | Review report for P7-T1 |
| [REVIEW_dedicated_host_frontend_docs.md](_Historical/REVIEW_dedicated_host_frontend_docs.md) | Review report for P6-T3 |
Expand Down Expand Up @@ -609,3 +611,5 @@
| 2026-03-07 | P6-T2 | Archived REVIEW_broker_terminal_frontend report |
| 2026-03-07 | P7-T2 | Archived Implement_a_broker_doctor_command_for_cross-black-box_diagnostics (PASS) |
| 2026-03-07 | P7-T2 | Archived REVIEW_broker_doctor_diagnostics report |
| 2026-03-07 | P7-T3 | Archived Auto-recover_or_guide_on_dashboard_port_ownership_conflicts (PASS) |
| 2026-03-07 | P7-T3 | Archived REVIEW_dashboard_port_ownership_conflicts report |
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# P7-T3 — Auto-recover or guide on dashboard port ownership conflicts

## Objective Summary

`P7-T1` introduced the explicit dedicated-host workflow and `P7-T2` gave users
one-command diagnostics, but the most confusing failure mode is still in the
startup path itself: `--broker-daemon --web-ui` can leave a running broker
behind while silently skipping the dashboard whenever the desired port is
occupied. That produces a partial state where the recommended frontend is down,
TUI cannot attach, and the user is forced to reason about multiple black boxes
at once.

`P7-T3` should remove that ambiguity. When users request the broker-hosted
dashboard, startup must either recover deterministically into a usable state or
stop with one explicit remediation path. The implementation should align
broker-daemon startup, broker-console orchestration, doctor messaging, and TUI
feedback around the same model so the user is never told that a degraded
dashboard-less host is “good enough”.

## Deliverables

- Tighten the broker-daemon startup path in
`src/mcpbridge_wrapper/__main__.py` so an explicit `--web-ui` request does not
silently degrade into “broker without dashboard”.
- Add shared logic that classifies dashboard port conflicts into actionable
buckets:
- healthy broker-backed dashboard already serving the port
- foreign or stale listener on the desired port
- local broker already running without dashboard on the desired port
- restart-eligible wrapper-owned listener when `--web-ui-restart` is used
- Update user-facing messaging so the failing command prints one clear next
action instead of continuing in a partial state.
- Extend doctor/TUI-facing guidance where needed so conflict explanations and
remediation text stay consistent with the startup behavior.
- Add regression tests for broker-daemon, broker-console, and diagnostics
scenarios that previously stranded users.

## Success Criteria

- `mcpbridge-wrapper --broker-daemon --web-ui` no longer leaves a healthy-seeming
broker running without the requested dashboard when the port cannot be used.
- Port conflicts resolve into one of two outcomes only:
- the requested broker-backed dashboard becomes available, or
- the command exits non-zero with an explicit remediation path
- `--broker-console` and `--doctor` surface the same conflict class and
recommended next action for the same runtime state.
- Tests pin both safe recovery and fail-fast behavior so future changes do not
reintroduce the hidden partial state.

## Test-First Plan

1. Add broker-daemon CLI tests that lock in the new fail-fast behavior when
`--web-ui` is requested but the target port is occupied by a foreign
listener, stale listener, or unusable existing runtime.
2. Add orchestration tests for `--broker-console` that verify it reuses a
healthy broker-backed dashboard, restarts only when explicitly permitted, and
reports a single remediation path for foreign ownership conflicts.
3. Add doctor classification/rendering tests for the updated conflict buckets so
diagnostics remain aligned with the startup behavior.
4. Only after the new expectations are pinned, implement the shared conflict
classifier and wire it into the daemon startup/orchestration flow.
5. Run required quality gates: `pytest`, `ruff check src/`, `mypy src/`, and
`pytest --cov`.

## Execution Plan

### Phase 1: Define the startup contract

Inputs:
- `src/mcpbridge_wrapper/__main__.py`
- existing broker-console/dashboard probe helpers
- `src/mcpbridge_wrapper/doctor.py`

Outputs:
- a clear contract for what counts as “dashboard ready”
- shared conflict categories for healthy reuse, recoverable ownership, and
explicit remediation
- deterministic stderr wording for broker-daemon and broker-console entrypoints

Verification:
- every dashboard startup branch ends in either usable dashboard availability or
non-zero failure
- no code path continues with `--web-ui` requested after a port conflict unless
the dashboard is actually reachable

### Phase 2: Implement shared conflict handling

Inputs:
- dashboard port probes and listener ownership helpers
- broker PID/socket/version state
- existing `/api/control` and `/api/broker/status` probes

Outputs:
- reusable conflict-resolution helper(s) for broker startup/orchestration
- explicit reuse path for already-healthy broker-backed dashboards
- fail-fast or restart-assisted path for foreign/stale ownership conflicts

Verification:
- running broker + healthy dashboard remains a no-op/reuse case
- foreign listeners and broker-without-dashboard states do not continue as
“success”

### Phase 3: Align diagnostics and finalize validation

Inputs:
- shared conflict results from startup/orchestration
- doctor and TUI user guidance
- unit and integration tests covering startup/diagnostic flows

Outputs:
- aligned doctor guidance for port ownership conflicts
- regression tests across broker-daemon, broker-console, and doctor
- validation report with required quality-gate output

Verification:
- the same runtime state yields the same diagnosis and remediation whether users
encounter it during startup, in TUI, or via `--doctor`
- no existing broker/web-ui/TUI entrypoints regress

## Acceptance Tests

- `pytest tests/unit/test_main.py`
- `pytest tests/unit/test_main_tui.py`
- `pytest tests/unit/test_doctor.py`
- `pytest tests/unit/test_tui.py`
- `pytest`
- `ruff check src/`
- `mypy src/`
- `pytest --cov`

## Decision Points

- Prefer fail-fast over silent degradation for explicit `--web-ui` requests; a
running broker without the requested dashboard is a broken UX state, not a
successful startup.
- Reuse the existing dashboard probe surfaces instead of inventing a second
ownership model just for startup recovery.
- Keep automatic recovery narrowly scoped to deterministic wrapper-owned cases;
otherwise print one clear remediation path and exit.

## Notes

- If implementation exposes common conflict helpers that both `doctor.py` and
`__main__.py` should consume, prefer that refactor now over duplicating
ownership logic again.
- The dedicated-host workflow introduced in `P7-T1` remains the product path;
messaging should continue to steer users toward `--broker-console` or
`--broker-daemon --web-ui`, not ad-hoc manual recovery.
- Review subject name for this task: `dashboard_port_ownership_conflicts`.

---
**Archived:** 2026-03-07
**Verdict:** PASS
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# P7-T3 Validation Report

**Task:** P7-T3 — Auto-recover or guide on dashboard port ownership conflicts
**Date:** 2026-03-07
**Verdict:** PASS

## Summary

Implemented the broker-hosted dashboard conflict fix by:

- removing the silent broker-daemon partial state where `--broker-daemon --web-ui`
could continue without the requested dashboard
- adding shared user-facing remediation helpers in
`src/mcpbridge_wrapper/__main__.py` so startup now resolves occupied-port
states into explicit attach, reset, or restart-assisted guidance
- aligning `--broker-console` conflict messaging with the dedicated-host
workflow already surfaced by `--doctor`
- preserving the safe recovery path via
`mcpbridge-wrapper --broker-console --web-ui-restart`
- extending unit coverage for foreign listeners, running brokers without a
dashboard, already-healthy broker-backed endpoints, and restart-assisted
recovery
- refreshing published coverage references in `README.md`,
`Sources/XcodeMCPWrapper/Documentation.docc/XcodeMCPWrapper.md`, and
`AGENTS.md` to the validated current total

## Files Validated

- `src/mcpbridge_wrapper/__main__.py`
- `tests/unit/test_main.py`
- `tests/unit/test_doctor.py`
- `README.md`
- `Sources/XcodeMCPWrapper/Documentation.docc/XcodeMCPWrapper.md`
- `AGENTS.md`

## Targeted Verification

```bash
pytest tests/unit/test_main.py tests/unit/test_main_tui.py tests/unit/test_doctor.py tests/unit/test_tui.py
```

- Result: `163 passed`

```bash
pytest tests/unit/test_main.py -k 'broker_console or broker_daemon_webui_port_occupied or broker_lacks_dashboard'
```

- Result: `18 passed`

```bash
python scripts/check_doc_sync.py --all --require-same-commit
```

- Result: `PASS`
- Observed outcome: README and DocC coverage references remained in sync after
updating the validated coverage metric

## Required Quality Gates

```bash
pytest
```

- Result: `887 passed, 5 skipped in 7.98s`

```bash
python -m ruff check src/ tests/
```

- Result: `All checks passed!`

```bash
mypy src/
```

- Result: `Success: no issues found in 20 source files`

```bash
make format-check
```

- Result: `55 files already formatted`

```bash
pytest --cov=src --cov-report=term
```

- Result: `887 passed, 5 skipped in 8.97s`
- Coverage: `91.62%`

## Notes

- The new startup contract is intentionally fail-fast for explicit `--web-ui`
requests. A running broker without the requested frontend is now treated as a
broken state, not a successful launch.
- Doctor messaging already matched the intended dedicated-host recovery path, so
this task focused on aligning startup/orchestration behavior to that model
instead of inventing a separate recovery surface.
- Remaining warnings are the pre-existing `websockets` / `uvicorn`
deprecations already visible in the repository test suite.
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
## REVIEW REPORT — dashboard_port_ownership_conflicts

**Scope:** origin/main..HEAD
**Files:** 11

### Summary Verdict
- [ ] Approve
- [x] Approve with comments
- [ ] Request changes
- [ ] Block

### Critical Issues

None.

### Secondary Issues

- [Medium] `src/mcpbridge_wrapper/__main__.py:604-640`,
`src/mcpbridge_wrapper/__main__.py:1072-1080`:
`_report_requested_dashboard_unavailable()` prioritizes
`running_broker_pid` over `listener_pids`. In the mixed state where a broker
PID is still live but the requested dashboard port is actually occupied by an
unrelated listener, both `--broker-console` and `--broker-daemon --web-ui`
will tell users to reset the broker first and omit the foreign port owner.
That remediation can loop back into the same conflict because the real
blocker, the non-broker listener on the port, was never surfaced. The
conflict classifier should prefer observable foreign port ownership or name
both blockers in one explicit recovery path.

### Architectural Notes

- The task correctly removes the most confusing partial state: explicit
dashboard startup no longer silently degrades into “broker alive, dashboard
absent”.
- Keeping `--broker-console --web-ui-restart` as the safe recovery path is the
right product choice; the remaining issue is about mixed-state prioritization,
not the core startup contract.
- Coverage-reference updates were kept in lockstep across README and the DocC
mirror, which avoids a repeat of the earlier documentation drift problem.

### Tests

- `pytest tests/unit/test_main.py tests/unit/test_main_tui.py tests/unit/test_doctor.py tests/unit/test_tui.py` passed (`163 passed`)
- `pytest` passed (`887 passed, 5 skipped`)
- `python -m ruff check src/ tests/` passed
- `mypy src/` passed
- `make format-check` passed
- `python scripts/check_doc_sync.py --all --require-same-commit` passed
- `pytest --cov=src --cov-report=term` passed with `91.62%` coverage

### Next Steps

- Add a focused follow-up task to improve mixed-state conflict prioritization
when a live broker PID and a foreign dashboard-port listener are both
observable.
Loading