From af385fc959d426be3ffd38f388270496863da926 Mon Sep 17 00:00:00 2001 From: deepfates Date: Wed, 23 Sep 2026 18:11:41 -0700 Subject: [PATCH 1/2] Move ex_mcp to 6b46670f with kite and haven The fork now returns a tool's result when output validation misses its deadline, instead of an error after the effect has happened. --- decisions.md | 2 +- mix.exs | 7 ++++--- mix.lock | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/decisions.md b/decisions.md index 1c290a13..33bae10c 100644 --- a/decisions.md +++ b/decisions.md @@ -17,7 +17,7 @@ not necessarily when it was made. | 2026-09-13 | Absorption renames: `IMP_ACP_PATH` becomes `IMP_PATH` (copied workspace example), `IMP_ACP_ROOT` becomes `IMP_ROOT` (host application preset), launcher is `examples/workspace_agent/scripts/workspace-agent-acp`. Module names `Imp.ACP`, `Imp.ACP.Host`, `Imp.ACP.MCP` and the `deepfates.com/imp-acp` wire metadata namespace keep their names. | Retired `imp_acp` README. Saved executable and environment references are updated explicitly, not by rewriting contact history. | In force. | Does not retire. | | 2026-09-13 | The workspace agent's session store keeps the `imp_acp/workspace_agent/sessions` directory name. | `examples/workspace_agent/README.md`. Preserves saved sessions; it is a storage location, not a dependency on the retired package. | In force. | Saved sessions are migrated, or the owner accepts losing restart continuity for them. | | 2026-09-13 | Ordinary Imp boot starts no protocol listener, subprocess or remote connection and does not start the ExMCP application. Protocol entry points (`Imp.ACP.*`, non-empty `Imp.MCP.connect/2`) start it explicitly. Releases using them declare `applications: [ex_mcp: :load]`. | `mix.exs` dependency comment, `docs/PRODUCTION_OPERATIONS.md` "Protocol runtime in releases", commit `728f8c77`. Prediction and optimizer processes must not open listeners or acquire protocol boot output. | In force. | Does not retire while Imp is a library inside a host application. | -| 2026-09-13 (pin dated 2026-09-15) | ExMCP is the `deepfates/ex_mcp` fork at `7285330b490476cc153dd60fb9adac9cd39d4a94`, the one ref shared with the other consumers of the same fork. Do not move it independently of them. | `mix.exs` `ex_mcp_dependency/0`; the fork's `FORK.md` records each patch (byte-safe stdio frames, owner-bound subprocess cleanup, ACP delivery barriers, per-connection HTTP trust) with its failure. Owner ruling, 2026-09-11: one ref, not one per consumer. | In force. | Each patch is upstreamed or made unnecessary and the dependency becomes a released Hex version; until then the ref moves for every consumer of the fork in one coordinated change. | +| 2026-09-13 (pin dated 2026-09-15) | ExMCP is the `deepfates/ex_mcp` fork at `6b46670f254846c9d19269def7f6fe3ffa2bea40`, the one ref shared with the other consumers of the same fork. Do not move it independently of them. | `mix.exs` `ex_mcp_dependency/0`; the fork's `FORK.md` records each patch (byte-safe stdio frames, owner-bound subprocess cleanup, ACP delivery barriers, per-connection HTTP trust, tool results kept when output validation misses its deadline) with its failure. Owner ruling, 2026-09-11: one ref, not one per consumer. | In force. | Each patch is upstreamed or made unnecessary and the dependency becomes a released Hex version; until then the ref moves for every consumer of the fork in one coordinated change. | | 2026-09-13 | `mix.exs` resolves ExMCP three ways: a bundled `vendor/ex_mcp` if present, else `EX_MCP_PATH`, else the GitHub pin. | `mix.exs`. No reason is recorded beside the conditional; the bundled path is presumably for the source package and the env override for fork development (*unverified*, inferred from `test/acp_imp_acp_test.exs` and the workspace agent test passing `EX_MCP_PATH` through). | In force, reason unrecorded. Conflicts with the standing rule (2026-09-11) that a new path deletes the old one; owner to rule. | The owner decides whether two of the three paths go, or records why all three stay. | | 2026-09-13 | Known interoperability limit, not a feature: when an HTTP MCP server selects protocol version `2025-03-26`, the pinned fork's `notifications/initialized` can still carry the client's `2025-11-25` header, and a strict older server may reject the session. Compatibility with strict older HTTP servers is not claimed. | `docs/PRODUCTION_OPERATIONS.md`, commit `902a5546`. Inherited from the fork's connection manager. | Open defect, documented. | The fork settles the HTTP version before sending that notification and a test against a strict older server passes. | | 2026-09-13 | Imported MCP tool calls disable generic transport retries, use ExMCP's `:safe_only` broken-stream policy, and never repeat an ambiguous write. The retired Imp-specific retry, backoff and Retry-After options are rejected, not ignored, and are not reimplemented above ExMCP. | `docs/PRODUCTION_OPERATIONS.md`. A timeout does not say whether the call ran; replay needs a real server idempotency contract, which is the application's to establish. | In force. | Does not retire. | diff --git a/mix.exs b/mix.exs index 76abf6b4..5cc1193d 100644 --- a/mix.exs +++ b/mix.exs @@ -123,8 +123,9 @@ defmodule Imp.MixProject do end # Shared fork reference. This fork carries byte-safe stdio, - # caller-owned request/subprocess cleanup, ACP delivery barriers, and - # per-connection HTTP trust propagation. See its FORK.md for each failure + # caller-owned request/subprocess cleanup, ACP delivery barriers, + # per-connection HTTP trust propagation, and tool results that survive a + # missed output-validation deadline. See its FORK.md for each failure # and retirement condition; do not move this ref independently of consumers. # Protocol adapters start ExMCP explicitly; ordinary prediction and optimizer # processes must neither start protocol services nor acquire their boot output. @@ -143,7 +144,7 @@ defmodule Imp.MixProject do true -> {:ex_mcp, github: "deepfates/ex_mcp", - ref: "7285330b490476cc153dd60fb9adac9cd39d4a94", + ref: "6b46670f254846c9d19269def7f6fe3ffa2bea40", runtime: false} end end diff --git a/mix.lock b/mix.lock index c978f0e2..45885bc7 100644 --- a/mix.lock +++ b/mix.lock @@ -17,7 +17,7 @@ "ex_aws_auth": {:hex, :ex_aws_auth, "1.4.1", "2f4faf59dd62933c52faf5c026f22b6b9b7d143cf30ee462204a646e3304761f", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: true]}], "hexpm", "42ea14c586689652f51906c797378a07822b65b32febd22067b4e93ff9dc7d4f"}, "ex_doc": {:hex, :ex_doc, "0.40.3", "4a972ffe64bc07dc605af487e98fc19b72a4185f55ca031b94c0552d6071c1d9", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "2756e357742fecd9749b489b85d67c9ce99c465f2e75728d9e6dc8d704b973de"}, "ex_json_schema": {:hex, :ex_json_schema, "0.11.5", "ea45f3238be135949dbbbcc9e8eb4682d6e561b8a66374e75d85a2e1d2bd4107", [:mix], [{:decimal, "~> 3.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "61ed2a8f07bd115e7ab6d45c147642a8c73b962bc419fadbb248046b9d3d0f20"}, - "ex_mcp": {:git, "https://github.com/deepfates/ex_mcp.git", "7285330b490476cc153dd60fb9adac9cd39d4a94", [ref: "7285330b490476cc153dd60fb9adac9cd39d4a94"]}, + "ex_mcp": {:git, "https://github.com/deepfates/ex_mcp.git", "6b46670f254846c9d19269def7f6fe3ffa2bea40", [ref: "6b46670f254846c9d19269def7f6fe3ffa2bea40"]}, "file_system": {:hex, :file_system, "1.1.1", "31864f4685b0148f25bd3fbef2b1228457c0c89024ad67f7a81a3ffbc0bbad3a", [:mix], [], "hexpm", "7a15ff97dfe526aeefb090a7a9d3d03aa907e100e262a0f8f7746b78f8f87a5d"}, "finch": {:hex, :finch, "0.23.0", "e3f9287ac25a8832f848b144c2b57346aac65b205e2e0629a52adfe6507fd837", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.8", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "80e58d3f936f57e3fdf404f83a3642897ae6d9fb642934e46da4d8fe761b99d5"}, "goth": {:hex, :goth, "1.4.5", "ee37f96e3519bdecd603f20e7f10c758287088b6d77c0147cd5ee68cf224aade", [:mix], [{:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:jose, "~> 1.11", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "0fc2dce5bd710651ed179053d0300ce3a5d36afbdde11e500d57f05f398d5ed5"}, From 3aeeb17a4f49caf29c574a80f83274f3793dfca1 Mon Sep 17 00:00:00 2001 From: deepfates Date: Wed, 23 Sep 2026 19:45:54 -0700 Subject: [PATCH 2/2] The deployment example's lock follows the ex_mcp move The dspy_parity tests run the example with IMP_PATH at this checkout, which resolves ex_mcp through the new pin and rewrote this lock during the run, so the calibration test found a dirty tree. --- examples/deployment/mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/deployment/mix.lock b/examples/deployment/mix.lock index 1c8f66af..fdac0eb0 100644 --- a/examples/deployment/mix.lock +++ b/examples/deployment/mix.lock @@ -9,7 +9,7 @@ "elixir_make": {:hex, :elixir_make, "0.10.0", "16577e2583a79bb79237bbff349619ef5d80afffc07eac6e4faf0d00e2ddaf7d", [:mix], [], "hexpm", "dc1f09fb7fa68866b886abd5f0f3c83553b1a19a52359a899e92af1bb3b31982"}, "erlexec": {:hex, :erlexec, "2.4.1", "73d2c49ecf3709cd7791a0affbef466a11cc1ecf9d679c504edbc9824b35c593", [:rebar3], [], "hexpm", "c92e1776eb1f7eee357a799cf399013dfa672ab50b4f507dfdcdeee11ca89769"}, "ex_json_schema": {:hex, :ex_json_schema, "0.11.5", "ea45f3238be135949dbbbcc9e8eb4682d6e561b8a66374e75d85a2e1d2bd4107", [:mix], [{:decimal, "~> 3.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "61ed2a8f07bd115e7ab6d45c147642a8c73b962bc419fadbb248046b9d3d0f20"}, - "ex_mcp": {:git, "https://github.com/deepfates/ex_mcp.git", "7285330b490476cc153dd60fb9adac9cd39d4a94", [ref: "7285330b490476cc153dd60fb9adac9cd39d4a94"]}, + "ex_mcp": {:git, "https://github.com/deepfates/ex_mcp.git", "6b46670f254846c9d19269def7f6fe3ffa2bea40", [ref: "6b46670f254846c9d19269def7f6fe3ffa2bea40"]}, "finch": {:hex, :finch, "0.23.0", "e3f9287ac25a8832f848b144c2b57346aac65b205e2e0629a52adfe6507fd837", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.8", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "80e58d3f936f57e3fdf404f83a3642897ae6d9fb642934e46da4d8fe761b99d5"}, "hpax": {:hex, :hpax, "1.0.4", "777de5d433b0fbdc7c418159c8055910faa8047ffdb3d6b31098d2a46cd7685c", [:mix], [], "hexpm", "afc7cb142ebcc2d01ce7816190b98ce5dd49e799111b24249f3443d730f377ca"}, "idna": {:hex, :idna, "7.1.0", "1067a13043538129602d2f2ce6899d8713125c7d19734aa557ce2e3ea55bd4f1", [:rebar3], [], "hexpm", "6ae959a025bf36df61a8cab8508d9654891b5426a84c44d82deaffd6ddf8c71f"},