DAN-872: mcp-demo settles over gRPC again — Sui deprecated JSON-RPC on public fullnodes - #7
Open
Danny-Devs wants to merge 5 commits into
Open
DAN-872: mcp-demo settles over gRPC again — Sui deprecated JSON-RPC on public fullnodes#7Danny-Devs wants to merge 5 commits into
Danny-Devs wants to merge 5 commits into
Conversation
…ee places it appeared `spec/vectors/` holds 167 vectors across 14 files. The repo said otherwise three different ways: README.md claimed 133, and docs/specification.md claimed 161 in two separate places. All three are now the real number. Two of those are cosmetic. The third is not. §13 "Conformance" criterion 5 is the NORMATIVE definition of what makes an implementation s402-conformant, so an implementer in Go, Python or Rust was told they conformed at 161 vectors — leaving six shipped vectors outside the definition of conformance. That clause now binds conformance to *every* shipped vector and carries the count as a version-anchored parenthetical rather than as the operative term. Also fixed: the README told readers to find the vectors by cloning the repo and running `ls test/conformance/vectors/`. That directory is generated by scripts/prepare-publish.sh at publish time and is git-ignored, so following the instructions in a fresh clone produced "No such file or directory". Clones are now pointed at `spec/vectors/`, and the relationship between the two paths is stated so the npm path stays right for package consumers. A count written into prose is a derived value maintained by hand — it rots silently on every vector added, and nothing fails when it does. Three independent wrong numbers is what that looks like once it has been running a while. So the fix is not only the numbers: test/spec-doc-counts.test.ts counts spec/vectors/ and compares it against every claim in both documents. The test is deliberately built to refuse a vacuous pass. If the wording changes so that no claim matches, it fails rather than silently verifying nothing — a check that cannot fail is not a check. It was watched to fail against four mutations before being kept: a wrong count in the spec, a wrong count in the README, a reworded claim, and a vector added without a doc update. It reads `spec/vectors/` and not `typescript/test/conformance/vectors/` on purpose. The latter is git-ignored build output; a check keyed there passes on any machine that has ever packed and is red on its first CI run. Also adds the README's missing "who this is for / who this is not for" and a falsification section naming four observable conditions that would retire the project — per the README convention's third question, which the doc set had nowhere to put. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…was claiming a CI check that never existed `Status: Accepted` has only ever meant DECIDED. It has never said BUILT — so an ADR that shipped and an ADR that was ratified and quietly never built were byte-identical on the page. All twelve records now carry an `Implementation:` field, each determined against the code rather than against the prose. The ratio this makes countable: 7 of 12 shipped, 1 upheld, 2 in-progress, 2 not-started. ADR-006 was the only record already carrying an `Implementation:` field, and it was false. It stated in the present tense that scripts/compute-scheme-digests.mjs "runs in CI and writes spec/scheme-digests.json", failing any PR that changed a scheme doc without updating the digests. Neither file appears in any commit on any branch, and CI's five jobs contain no such gate. So the project's single answer to "was this built?" was a claim that read as verified precisely because it sat in the slot reserved for verified things. The paragraph is now marked as an unbuilt plan. Two findings fell out of doing this honestly: ADR-004's extensions framework ships as the `s402/extensions` subpath in package.json while its Status still reads Proposed — built without the decision ever being accepted. Status is left untouched: flipping a governance field is a decision, not a cleanup. ADR-010's S16 is half-built. Searching for the label found one narrative mention; searching for the MECHANISM found the protocol version genuinely bound into the signed envelope and required at envelope.ts:268. Its scheme-digest half is blocked on ADR-006, which is not-started. Grepping for a rule's name finds where someone wrote the name; grepping for its mechanism finds where it is enforced. Where the evidence is a search rather than a proof, the field says so — the negatives are recorded as "no witness found", not as "proven absent". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tranger meets it Sui has deprecated JSON-RPC on public fullnodes. Every core method returns -32601 on testnet AND mainnet, verified directly on both rather than taken from a report. mcp-demo/src/server.ts and src/agent.ts both construct a SuiClient over that transport, and docs/guide/tutorial.md's "Making It Real" snippet tells readers to do the same. This is a hole in the done-bar item I had just called satisfied. Item 1 is "a stranger can run the one demo in 10 minutes", and I had verified the README's CLAIMS — paths, counts — without ever running the demo. The grant-ready standard I authored says to enumerate every shipped surface; I applied that to test suites and missed the runnable artifact, which is the surface the stranger test is actually about. The fix here is honesty, not repair: both surfaces now state the blocker above the instructions, so nobody follows a dead path. The migration to gRPC/GraphQL is tracked separately and is not attempted inside a documentation pass. Both notices are to be removed by that work — a stale blocker warning is its own defect, so the removal is written into that ticket's done-bar. Worth recording what did NOT break: typescript/package.json has no Sui dependency and never had one (ADR-002, invariant S7, enforced by the S7 Chain-Agnostic Boundary CI job). The entire protocol layer — encoding, validation, conformance vectors, all 1108 tests — runs offline and is untouched. The blast radius is exactly one demo and one snippet. That containment is the pure-protocol decision paying out, and it is the strongest evidence for S7 the repo has produced so far. Raised cross-lane by agent-b g11 from the SweeFi pass; verified independently before acting. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… rejects payments that landed
Sui deprecated JSON-RPC on public fullnodes, which left mcp-demo dead at the
network layer. Both touchpoints now use SuiGrpcClient.
The endpoint is unchanged. gRPC is served from the same host and port, so this
is a client swap and not an endpoint move.
Requires @mysten/sui 2.x, and that is not incidental. On the 1.45.2 the caret
had resolved to, executeTransaction is rejected by current fullnodes with
"invalid read_mask path: transaction.transaction", and neither the gRPC nor the
GraphQL client can resolve a transaction for building. The write path cannot be
migrated on 1.x at all.
Four shape changes, each of which type-checks and then misbehaves:
- balanceChanges is present-but-undefined unless requested via `include`. Left
out, the credit check runs over undefined, returns false, and the demo
rejects every real payment while looking like a working payment gate.
- Responses are protobuf-wrapped as a union discriminated on $kind; the payload
is at .Transaction, and the failure arm carries it under another key.
- Balance changes are flat {coinType,address,amount}; JSON-RPC nested the
recipient under owner.AddressOwner.
- Execution status is a boolean discriminant, not status.status === 'success'.
Also adds a bounded retry to the verifying read. getTransaction returns
NOT_FOUND immediately after an execute that already reported success, because
the public endpoint is load-balanced and the read can reach a node that has not
caught up. Observed: first read NOT_FOUND, second read ~4s later succeeds.
Without the retry the demo intermittently rejects settled payments, and does so
more often on a fast machine.
Verified end-to-end on testnet, not compiled:
agent settles 7cVD9Z7SirgNhJYQMgaUcjnsbivfGcWFp5Fnozxg4WpX
effects.status success
balanceChanges receiver +10000000, sender -11997880 (amount + gas)
server verifies tool result returned
negative control bogus digest rejected with -32402
The negative control matters: an earlier run passed against a stale
envelope-only server, whose verifier returns true without touching the chain.
That was a false green. The gate was re-proven able to fail before this was
called done.
typescript/src is untouched, so S7 holds.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…out is fixed The notices in mcp-demo/README.md and docs/guide/tutorial.md said the demo could not reach the network and that they would be removed when the migration landed. It landed in the previous commit, so they go in the same PR — a stale blocker warning is its own defect, and this one would now be actively false. The tutorial snippet is updated to the transport that works: SuiGrpcClient, an explicit tx.setSender (the gRPC client has no signAndExecuteTransaction to infer it from), and a note that this needs @mysten/sui 2.x. Two README claims the migration made untrue are corrected: the declared dependency (^1.18.0 -> ^2.24.0) and the verification path, which is no longer SuiClient.getTransactionBlock. The retry on the verifying read is documented where someone reading the settlement flow will meet it. Deliberately NOT changed: "Demo returns a 501 JSON-RPC error" further down that README. That JSON-RPC is MCP's own wire protocol, not Sui's node RPC, and it is still correct. Only Sui's transport was deprecated. docs/guide/quickstart.md also mentions @mysten/sui and still carries no notice. That is correct rather than an oversight: it names no transport, constructs no client and points at no fullnode, so it stayed true throughout. The SDK did not die, the JSON-RPC transport did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Base automatically changed from
agent-a/DAN-855-spec-vector-count-and-stranger-test
to
main
August 16, 2026 23:19
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this fixes
mcp-demo— the runnable artifact a reviewer reaches for after the README — was dead at the network layer. Sui deprecated JSON-RPC on public fullnodes; every core method answers-32601on testnet and mainnet alike. Both the agent and the server constructed aSuiClientover that transport.Stacked on #6. It has to be: the blocker notices this PR removes were added there and do not exist on
main. Merge #6 first.Verified end-to-end, not compiled
The done-bar asks for an observed payment, so:
The negative control is load-bearing. An earlier run passed against a stale envelope-only server, whose verifier returns
truewithout touching the chain — a false green that looked identical to success. The gate was re-proven able to fail before this was called done.This needed an SDK major, and that is the part worth knowing
mcp-demodeclared^1.18.0, which had resolved to 1.45.2. On 1.x this migration is not possible, not merely awkward:core.executeTransactionINVALID_ARGUMENT: invalid read_mask path: transaction.transactiontx.build({ client: grpc })Transaction resolution is not supported with the GRPC clienttx.build({ client: graphql })GraphQL client does not support transaction resolution yetReads work on 1.x; settlement cannot. All three clear on 2.24.0.
The endpoint did not change
gRPC is served from the same host and port as the dead JSON-RPC. No config, env var or README URL needed updating. Worth saying plainly, because "migrate to gRPC" reads like an endpoint move and it is not.
Four shape changes that type-check and then misbehave
balanceChangesis present-but-undefinedunless requested viainclude. Omit it and the credit check runs overundefined, returnsfalse, and the demo rejects every real payment — failing closed, which is the safe direction and therefore the one nobody notices.$kind; the payload is at.Transaction, and the failure arm carries it under a different key.{coinType, address, amount}; JSON-RPC nested the recipient underowner.AddressOwner.status.status === 'success'.A behavioural fix that was not in the ticket
getTransactionreturnsNOT_FOUNDimmediately after an execute that already reported success — the public endpoint is load-balanced, so the verifying read can reach a node that has not caught up. Observed: first readNOT_FOUND, second ~4s later succeeds.Ported literally, the server would intermittently reject settled payments, more often on a fast machine — the worst failure signature for a demo a stranger runs. The verify path now retries on
NOT_FOUNDwithin a bounded window.S7 holds
typescript/srcis untouched. The demo is expected to import@mysten/sui— ADR-011 Alternative A rejected promoting it into core for exactly that reason. The S7 boundary test is green.Verification
Re-run after the restack, since a rebase invalidates every prior green run.
🤖 Generated with Claude Code