CHANGELOG.md
Rama main · réplica de lectura del repositorio original.
# 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