# Changelog Notable changes to Parley. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Entries cover user-visible changes (library API, examples, live demo); routine doc and dependency commits are omitted. ## [Unreleased] ## [0.2.1] - 2026-10-25 ### Added - `parley-mcp` is dual-era. It serves the MCP 2026-07-28 revision statelessly (per-request `_meta`, `resultType`, `ttlMs`/`cacheScope` on `tools/list`, `server/discover`, error -32022 `UnsupportedProtocolVersion` with the supported list) next to the existing `initialize` handshake, so hosts that move to the new revision keep working. Legacy sessions are unchanged apart from `initialize` now also accepting `2025-11-25`; a request that carries `io.modelcontextprotocol/*` per-request `_meta` is treated as a 2026-07-28 request, so such a request without a protocol version now returns `-32602`. Tool names and decisions are untouched. ### Security - `Agent.consider` reports a constant `score` of 0.0 on a red-lined verdict instead of the owner's real soft score, so a rejected option reveals only `acceptable=False` and `reason="red-line"`. Decisions are unchanged (max-min only ranks options every party accepts), but every new transcript hash differs; receipts issued earlier still hash and verify. ### Fixed - `Transcript.hash()`, `verdict_payload` and `acceptance_payload` no longer hash or sign a tuple option/decision the same as an equal-valued list; a dict carrying the reserved key `__tuple__` is refused rather than allowed to collide with the tag. A record built with a live tuple hashes differently from its own JSON export (JSON has no tuple type, so `from_dict` always rebuilds it as a list) — `verify_outcome`, `verify-receipt.py` and `ratify.agreement` all report that mismatch honestly rather than treating it as agreement (the hash check itself is the MCP `parley_verify_receipt` tool and `scripts/verify-receipt.py`, not `verify_outcome`, which checks the max-min outcome instead). Pass JSON-native options (lists, not tuples) if a record needs to round-trip through JSON and still verify. ## [0.2.0] - 2026-09-26 ### Added - `parley/mcp.py`: a stdlib-only MCP server over stdio (`parley-mcp` console script, or `python -m parley.mcp`) so Claude Desktop, Claude Code and Cursor can call Parley as a tool. Three tools: `parley_decide` (a `DecisionSpec` in, status + decision + transcript + `transcript_sha256` out), `parley_verify_receipt` (recompute the hash over a transcript, and `max_min_verified` via `verify_outcome` over its recorded verdicts) and `parley_check_party` (replay one party's red lines against a decision). In this mode the host holds every party's spec, so there is no privacy from the host; red lines and max-min still hold, and the receipt is tamper-evident provided the hash is kept by someone other than whoever might edit the transcript (it is unsigned and the server does not store it). Private sheets need one process per owner (`examples/run_env.py`). A spec is bounded to 500 options, 50 parties, 10 000 option×party evaluations and 1000-item constraint lists; larger ones return a tool error. - `parley/ratify.py`: an owner's explicit accept of a finished parley, bound to the decision and the transcript hash. `ratify()` refuses an accept that the submitted sheet rejects; `agreement()` is unanimous over one exact record and fails closed on a stale hash, a swapped decision, a rejection, a stranger or a missing owner. Unsigned acceptances are tamper-evidence only. - `examples/real_decision.py`: the end-to-end flow for running a decision with real people at one keyboard. Public option set, private positions taken one person at a time, natural-language entry through `elicit` (or a manual mode with no model involved), then per-owner local ratification. The receipt reports unanimous acceptance and honest max-min separately. - `parley/elicit.py`: natural-language → `PreferenceSheet` extraction behind a pluggable `Elicitor` interface — the LLM boundary stays outside the zero-dependency core (#46). - `verify_outcome()` in `parley/consensus.py`: recompute the max-min result from the public transcript alone, so a coordinator cannot misreport the winner (v0.2 security fix 1 of 3) (#34). - `--json` flag on `examples/run_env.py` for machine-readable consensus output (#31). - Live demo: estate-valuation recipe made runnable, plus proof cards, recipe provenance, and SEO files (#42, #43). - Live demo promoted to six scenarios with the Partnership and DAO treasury recipes (#18). - Tests covering transcript tamper-evidence edge cases — first external contribution (#21). ### Changed - Distribution renamed to `parley-consensus` (PyPI's `parley` is an unrelated project); the import name stays `parley`. The wheel now ships `parley.net` (signed verdicts, HTTP bots): the hand-written `packages = ["parley"]` left the subpackage out of `0.1.0`'s build. `tests/test_packaging.py` guards both. - A red-line predicate now passes only when it returns exactly `True`. Any other value crosses the red line, including truthy non-bools: `lambda o: o.get("flag")` used to pass on any non-empty value and now counts as a crossing. This is the change most likely to affect existing sheets — return a real `bool` from every predicate. - `PreferenceSheet.evaluate()` raises `ValueError` when the utility returns NaN. The old clamp turned NaN into a score of 1.0. - `run_consensus()` with no agents returns an honest deadlock instead of crashing, and refuses duplicate owner names or an unknown `rule` with `ValueError` before any agent is asked. - `verify_outcome()` returns `False` when any entry is missing an owner's verdict, carries an owner twice, or has a different owner set from the other entries. Before, a coordinator could drop one owner's veto from the entry it wanted to win and the recomputation agreed with it. - `verify_outcome()` takes an optional `expected_owners=`: when given, every entry's owner set must equal it exactly. Without it, a coordinator that drops one owner from every entry, or the lone veto in a one-option record, still passes. `scripts/verify-receipt.py` passes the receipt's `participants` (coordinator-written, as its output now says) and now names the owner-set mismatch explicitly (the existing roster check already failed such receipts). When `participants` is malformed, the max-min line fails as "owner set unchecked"; `participants: null` no longer crashes the script. - `RemoteAgent.consider()` raises `ValueError` when the bot's card advertised a `pubkey_hex` and the reply carries a different key or no signature. Before, a party between the coordinator and a signed bot could sign verdicts with its own key and `verify_transcript()` accepted them. Bots whose card has no key are unaffected. The client checks that a signature is present under the card's key; whether the signature is valid is checked by `verify_transcript(require_signed=True)`, which `examples/run_env.py` now runs (exiting non-zero on failure) and any other caller must run. ### Fixed - Static demo build now carries the proof cards and brand assets (#45). - SHA-256 receipt hash wraps instead of overflowing its box (#19). ### CI - Hosted demo builds and deploys on merge (#44); Python 3.14 added to the test matrix (#33); Dependabot version/security updates with patch/minor auto-merge (#22, #29). ## [0.1.0] - 2026-07-24 First tagged release. Repo went public 2026-07-18. ### Added - Zero-dependency core: private `PreferenceSheet` with hard red lines as code predicates (`preferences.py`), masked `Verdict`s that never expose the sheet (`agent.py`), max-min consensus with honest deadlock (`consensus.py`), and a tamper-evident SHA-256 transcript with per-owner `verify_non_betrayal` replay (`transcript.py`). - Networked mode: each bot as its own OS process behind a hardened HTTP server (`net/bot.py`), optional Ed25519-signed verdicts (`net/identity.py`), and a `RemoteAgent` client that makes the consensus core transport-agnostic (`net/client.py`). - Runnable examples: `meeting.py` (in-process, with `--json`) and `run_env.py` (consensus over HTTP) (#5). - Live demo at [parleyprotocol.com](https://parleyprotocol.com) with the committee grant vote recipe (#7). - Site polish: footer, favicon, PWA manifest, `llms.txt` (#11, #12). ### Fixed - Demo scenario tabs are keyboard-reachable with focus and key activation (#10). [Unreleased]: https://github.com/5uper0/parley/compare/v0.2.0...HEAD [0.2.0]: https://github.com/5uper0/parley/releases/tag/v0.2.0 [0.1.0]: https://github.com/5uper0/parley/releases/tag/v0.1.0