Skip to content

Commit f21f420

Browse files
vosesoftclaude
andcommitted
Housekeeping: CHANGELOG + gated live integration tests (gap #7)
Add CHANGELOG.md documenting 0.0.1–0.0.19. Add tests/test_integration.py: live COM tests (attach + list_trees + rollback-vs-MC_V_ cross-check), skipped unless MODELCHOICE_LIVE=1 with a ModelChoice workbook open — a regression harness for the GetActiveObject attach fix. 56 pass, 2 skipped; ruff + mypy clean. 0.0.19. Deferred: passing the sheet name from the build_control_panel bridge call — the currently-installed add-in's command is 0-param (an extra arg would break it); will wire once the AB#2615 build ships. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 778e887 commit f21f420

5 files changed

Lines changed: 108 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Changelog
2+
3+
All notable changes to `modelchoice-mcp`. Versions are tag-driven; pushing a
4+
`vX.Y.Z` tag publishes to PyPI via the release workflow.
5+
6+
## 0.0.19
7+
- **Housekeeping** — CHANGELOG; gated live integration tests
8+
(`MODELCHOICE_LIVE=1`) exercising the real COM attach/read/rollback path.
9+
10+
## 0.0.18
11+
- **Knowledge resources**`modelchoice://guide/*` curated decision-analysis
12+
guidance (building trees, EVPI vs EVII, which analysis to use, pitfalls).
13+
14+
## 0.0.17
15+
- **Import / export**`export_tree_json` (a tree's raw ModelChoice JSON, to
16+
save/share/version) and `import_tree_json` (validate raw JSON → write/render).
17+
18+
## 0.0.16
19+
- `run_decision_report` gains **`force_to_outcome`** (what inputs would have to
20+
change to force a chosen outcome).
21+
22+
## 0.0.15
23+
- **`run_risk_profile`** — per-option outcome distribution (expected value, min,
24+
max, std dev + the cumulative-probability table), not just the EV.
25+
26+
## 0.0.14
27+
- **`run_scenarios`** — what-if comparison: named bundles of input edits, each
28+
rolled back and compared to the baseline (EV, optimal decision, Δ, flips).
29+
30+
## 0.0.13
31+
- **Excel attach fix** — bind to the running Excel via `GetActiveObject` (ROT)
32+
instead of xlwings' window-handle walk, which failed (`0x800A01A8`) once the
33+
ModelChoice add-in was loaded. Fixes timeouts/hangs from the MCP server.
34+
35+
## 0.0.12
36+
- **`build_control_panel`** — lift a tree's inputs into a labelled control panel
37+
at the top of its sheet, with the tree linked back to it.
38+
39+
## 0.0.11
40+
- `edit_tree` gains structural ops: `add_option`, `add_branch`, `remove_branch`.
41+
42+
## 0.0.10
43+
- **`run_evii`** — Expected Value of Imperfect Information for a specific test.
44+
45+
## 0.0.9
46+
- **`run_decision_report`** — strategy table / policy / decision brief / MCDA.
47+
48+
## 0.0.1 – 0.0.8
49+
- Phases 0–2: read + rollback engine (`list_trees`, `get_tree`, `roll_up`,
50+
`verify_rollback`), build/edit (`build_tree`, `edit_tree`), and analysis
51+
drivers (`run_evpi`, `run_robustness`, `run_sensitivity`, `run_analysis`,
52+
`read_sheet`), plus the `/design-decision-tree` prompt. CI + tag-driven PyPI
53+
release. First PyPI publish at 0.0.1.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "modelchoice-mcp"
3-
version = "0.0.18"
3+
version = "0.0.19"
44
description = "An open Model Context Protocol server for Vose Software's ModelChoice decision-tree add-in for Excel."
55
readme = "README.md"
66
requires-python = ">=3.11"

src/modelchoice_mcp/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
"""ModelChoice MCP — an open Model Context Protocol server for Vose
22
Software's ModelChoice decision-tree add-in for Excel."""
33

4-
__version__ = "0.0.18"
4+
__version__ = "0.0.19"

tests/test_integration.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""Gated live integration tests against a real Excel + ModelChoice add-in.
2+
3+
These are SKIPPED unless MODELCHOICE_LIVE=1 and a workbook with at least one
4+
ModelChoice tree is open. They exercise the real COM bridge (no fakes) — the
5+
attach, read, and rollback path — and serve as a regression harness for the
6+
GetActiveObject attach fix (0.0.13). Run with:
7+
8+
MODELCHOICE_LIVE=1 uv run pytest tests/test_integration.py -v
9+
10+
Read-only by default; they never write to the workbook.
11+
"""
12+
13+
from __future__ import annotations
14+
15+
import os
16+
17+
import pytest
18+
19+
pytestmark = pytest.mark.skipif(
20+
os.environ.get("MODELCHOICE_LIVE") != "1",
21+
reason="live Excel test; set MODELCHOICE_LIVE=1 with a ModelChoice workbook open",
22+
)
23+
24+
25+
@pytest.fixture
26+
def live_bridge():
27+
from modelchoice_mcp.bridge import ModelChoiceBridge
28+
29+
return ModelChoiceBridge()
30+
31+
32+
def test_attach_and_list(live_bridge) -> None:
33+
"""The bridge attaches to the running Excel and finds at least one tree."""
34+
trees = live_bridge.list_trees()
35+
assert isinstance(trees, dict)
36+
assert trees, "no ModelChoice trees in the active workbook"
37+
38+
39+
def test_roll_up_matches_rendered_cells(live_bridge) -> None:
40+
"""Our Python rollback agrees with the add-in's own MC_V_ cells (when the
41+
tree has been rendered)."""
42+
trees = live_bridge.list_trees()
43+
name = next(iter(trees))
44+
result = live_bridge.roll_up(name)
45+
assert result.expected_value == pytest.approx(result.expected_value)
46+
47+
cells = live_bridge.read_node_values()
48+
if not cells:
49+
pytest.skip("tree not rendered (no MC_V_ cells) — open it in ModelChoice")
50+
for node_id, node in result.node_results.items():
51+
if node_id in cells:
52+
assert node.expected_value == pytest.approx(cells[node_id], abs=0.01)

tests/test_server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88

99
def test_version_set() -> None:
10-
assert __version__ == "0.0.18"
10+
assert __version__ == "0.0.19"
1111

1212

1313
def test_server_name() -> None:

0 commit comments

Comments
 (0)