Skip to content

feat(734): plugin loader skeleton for PEP 1.7.0#758

Merged
TSavo merged 7 commits into
mainfrom
feat/734-plugin-loader-skeleton
May 12, 2026
Merged

feat(734): plugin loader skeleton for PEP 1.7.0#758
TSavo merged 7 commits into
mainfrom
feat/734-plugin-loader-skeleton

Conversation

@TSavo
Copy link
Copy Markdown
Owner

@TSavo TSavo commented May 12, 2026

Closes #734. Part of the #732 plugin-protocol umbrella.

Summary

Runtime engine for PEP 1.7.0. Implements the spec at protocol/specs/2026-05-12-plugin-protocol.md (PR #740). No concrete plugin implementations ship in this PR -- only the loader infrastructure.

New crate: provekit-plugin-loader

Spec sections implemented:

Section What
§1 PluginMemento, PluginEnvelope, PluginHeader, PluginMetadata wire types (CDDL-matching)
§3 load_plugin_from_file: parse JSON, shape-validate, protocol-version check, CID verify
§4 load_plugin_from_rpc: stdio spawn + provekit.plugin.describe dispatch; HTTP/TCP stubs with rpc-error
§6 compute_plugin_cid: JCS over header-without-cid, BLAKE3-512. protocol_versions sorted ascending before JCS. §6.2 delivery-independence invariant tested.
§8 PluginLoadFailureMemento, FailureReasonKind (all canonical labels), mint_failure_memento, compute_failure_cid
§9 PluginRegistry: BTreeMap<(kind, cid), PluginMemento>, register, lookup, by_kind, register_builtin, record_failure, emit_registry_memento. PluginRegistryMemento + compute_registry_cid. Built-ins appended AFTER user flags per §7.

Fixture: tests/fixtures/dummy-sugar.json -- kind = "test:dummy" open-enum label, pinned CID blake3-512:ad148c5f.... The CID is verified on every cargo test run by file_load_valid_fixture.

CLI plumbing (provekit-cli)

New cmd_plugin.rs module + PluginFlags struct:

Flag Effect
--plugin <kind>:<source> Canonical form (§7)
--sugar <source> Alias: --plugin sugar:<source>
--loss-fn <source> Alias: --plugin loss-function:<source>
--lifter <source> Alias: --plugin lift:<source> (wire kind = "lift", §2.1)
--no-default-plugins Suppress ALL built-ins
--no-default-plugin <kind> Suppress built-ins for one kind
--strict-plugins Promote every failure to refuse
--plugin-registry-out <path> Write PluginRegistryMemento JSON

BindArgs gains #[command(flatten)] pub plugins: PluginFlags. The run() function seals the registry before pipeline work and logs the registry CID prefix. The _registry_cid variable is plumbed for §9.4 provenance citation by downstream pipeline steps.

Tests

16 unit (in src/):

  • cid::tests::cid_elides_cid_field -- CID input never includes the cid field
  • cid::tests::protocol_versions_sort_is_applied -- unsorted vs sorted produce same CID
  • cid::tests::failure_cid_is_deterministic -- §8.3 stability
  • registry::tests::register_and_lookup -- (kind, cid) round-trip
  • registry::tests::lookup_miss_returns_none
  • registry::tests::by_kind_returns_all_of_kind
  • registry::tests::duplicate_cid_deduplication -- §9.2
  • registry::tests::emit_registry_memento_round_trip -- §9.1
  • registry::tests::registry_cid_is_stable_across_calls -- §9.3 byte-stability
  • registry::tests::failure_memento_minting
  • registry::tests::builtin_count_tracks_register_builtin -- §7 built-in ordering
  • loader::tests::load_file_not_found
  • loader::tests::load_file_parse_error_on_bad_json
  • loader::tests::load_file_missing_header_field
  • loader::tests::rpc_http_stub_returns_rpc_error
  • loader::tests::rpc_unknown_scheme_returns_rpc_error

8 integration (in tests/integration.rs):

  • file_load_valid_fixture -- pinned CID assertion (byte-stability)
  • file_load_round_trip_cid -- §6.2 delivery-independence (file path)
  • file_load_nonexistent_returns_file_not_found_error -- §8 error model
  • failure_memento_for_nonexistent_file -- §8.1 + §8.3 deterministic CID
  • registry_lookup_by_kind_cid -- §9 (kind, cid) lookup
  • registry_memento_includes_loaded_cid -- §9.1 + §9.4 registry CID present
  • rpc_stdio_load_valid -- §4 stdio RPC via stub_rpc_server binary
  • rpc_stdio_registry_cid_matches_file_load_when_payload_identical -- §6.2

Out of scope (skeleton)

  • ProtocolBlessingMemento (§14) -- follow-on
  • provekit.plugin.invoke / .shutdown (§4.2.2/.3) -- only describe needed for load
  • HTTP/TCP RPC -- stubbed with rpc-error; follow-on
  • Full CDDL validation of content payload -- consumer specs validate (§1.2)
  • Ed25519 signature verification -- parsed and stored; full verify is a TODO

Follow-on sub-issues

Test plan

  • cargo check -p provekit-plugin-loader -- clean (0 warnings)
  • cargo check -p provekit-cli -- clean (3 pre-existing dead-code warnings, not introduced here)
  • cargo test -p provekit-plugin-loader -- 24/24 pass (16 unit + 8 integration)
  • CI: make test-rust (full workspace gate on spec/plugin-protocol base)

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added plugin loader system with support for file and JSON-RPC stdio-based plugin loading.
    • Introduced plugin registry for managing, validating, and sealing loaded plugins.
    • Extended CLI with plugin management flags (including --plugin, --strict-plugins, and --plugin-registry-out).
  • Chores

    • Updated protocol specifications and attestation digests.
    • Adjusted build configuration for Maven dependency resolution.

Review Change Stack

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

Warning

Rate limit exceeded

@TSavo has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 41 minutes and 9 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 762d8af3-03e2-4892-a664-bcba03919300

📥 Commits

Reviewing files that changed from the base of the PR and between 76d4810 and a7cd207.

📒 Files selected for processing (1)
  • implementations/rust/provekit-cli/tests/mint_kit_integration.rs

Walkthrough

This PR implements PEP 1.7.0 plugin loading and registry management through a new provekit-plugin-loader Rust crate integrated into the CLI. The loader supports file-based and JSON-RPC plugin sources, validates plugin CIDs deterministically, and accumulates plugins into a sealed registry memento. Supporting attestation digests and contract pins are updated to reflect the new implementation.

Changes

Plugin Loader System

Layer / File(s) Summary
Plugin memento and registry wire types
implementations/rust/provekit-plugin-loader/src/types.rs
Serde-serializable type definitions for plugin envelopes, headers, metadata, failure mementos, and registry snapshots with convenience accessors for CID, kind, and criticality checks.
CID computation and error handling
implementations/rust/provekit-plugin-loader/src/cid.rs, implementations/rust/provekit-plugin-loader/src/error.rs
Deterministic JCS/BLAKE3-512-based CID computation for plugins, failures, and registries. LoadError enum maps loader failures to structured reason kinds and detail messages.
Plugin loading from file and RPC sources
implementations/rust/provekit-plugin-loader/src/loader.rs
Implements load_plugin_from_file and load_plugin_from_rpc with centralized validation: schema version enforcement, protocol version matching against pep/1.7.0, and CID verification. Supports stdio: JSON-RPC and rejects unimplemented transports.
In-memory registry and memento emission
implementations/rust/provekit-plugin-loader/src/registry.rs
PluginRegistry accumulates loaded plugins and failures, deduplicates (kind, cid) pairs, tracks built-ins, and emits sealed PluginRegistryMemento with load order preservation and CID-sorted entries.
Plugin loader fixtures and integration tests
implementations/rust/provekit-plugin-loader/tests/fixtures/dummy-sugar.json, implementations/rust/provekit-plugin-loader/tests/integration.rs, implementations/rust/provekit-plugin-loader/src/bin/stub_rpc_server.rs
Test fixture, stub JSON-RPC server binary, and comprehensive integration tests covering file loading, RPC dispatch, failure memento generation, registry semantics, and delivery-independence via content-addressed CID matching.
Plugin loader crate manifest and exports
implementations/rust/provekit-plugin-loader/Cargo.toml, implementations/rust/provekit-plugin-loader/src/lib.rs
Cargo manifest with library and binary targets, workspace and external dependencies. lib.rs declares internal modules and re-exports the public loader API.
CLI plugin flag parsing and registry building
implementations/rust/provekit-cli/src/cmd_plugin.rs
New PluginFlags struct with manual clap::Args/clap::FromArgMatches preserving argv order across interleaved aliases. build_registry loads plugins in recovered order, validates kinds, handles failures (critical vs --strict-plugins), and optionally outputs registry memento as JSON.
Bind command plugin registry sealing
implementations/rust/provekit-cli/src/cmd_bind.rs
BindArgs flattened to include PluginFlags. run() seals plugin registry at startup by computing timestamp, calling build_registry, handling refusal with error message, and capturing sealed registry CID for downstream provenance logic.
Workspace integration and CLI re-exports
implementations/rust/Cargo.toml, implementations/rust/provekit-cli/Cargo.toml, implementations/rust/provekit-cli/src/main.rs
Adds provekit-plugin-loader to workspace members. Adds dependencies on provekit-plugin-loader and chrono in CLI. Declares cmd_plugin module and re-exports PluginFlags with PEP 1.7.0 documentation.

Self-Contract Attestations and Protocol Catalog Updates

Layer / File(s) Summary
Self-contract attestation digests
.provekit/self-contracts-attestations/csharp.json, .provekit/self-contracts-attestations/go.json, .provekit/self-contracts-attestations/java.json, .provekit/self-contracts-attestations/ruby.json, .provekit/self-contracts-attestations/rust.json
Updated CID and signature values in all five language attestations reflecting current plugin protocol specs; schema version and signer fields remain stable.
Protocol catalog and self-contracts pins
protocol/specs/2026-04-30-protocol-catalog.json, implementations/rust/provekit-self-contracts/src/lib.rs
Updated agent-plugin-protocol and lift-plugin-protocol blake3-512 digests in catalog. Updated ACCEPTED_LIFT_PLUGIN_PROTOCOL_CONTRACT_SET_CID constant to reflect current lift-plugin-protocol contract set.
Integration test pins and build tooling
implementations/rust/provekit-cli/tests/mint_kit_integration.rs, tools/cross-kit-conformance/src/lib.rs
Updated GO_CONTRACT_SET_CID pinned test value to reflect 11-contract Go slab. Changed Maven lifecycle phase from package to install in cross-kit-conformance for proper dependency resolution timing before classpath build step.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • TSavo/provekit#732: Main plugin protocol umbrella issue; this PR implements the plugin loader skeleton per #732's specification for JSON file loading, JSON-RPC harness, CLI flags, and registry mechanics.

Possibly related PRs

  • TSavo/provekit#474: Both modify self-contract attestation JSONs and cross-kit conformance bootstrapping artifacts.
  • TSavo/provekit#480: Both update the same ACCEPTED_LIFT_PLUGIN_PROTOCOL_CONTRACT_SET_CID self-contracts pin and related attestations.
  • TSavo/provekit#6: Both update protocol catalog digests for plugin-related specs including lift-plugin-protocol.

Poem

A loader leaps through JSON streams, 🐰
Registry dreams of plugins sealed,
CIDs computed, order preserved,
CLI flags make plugins retrieved,
Attestations dance with fresh digests!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(734): plugin loader skeleton for PEP 1.7.0' directly and clearly refers to the PR's primary change: implementing a plugin loader skeleton for PEP 1.7.0, matching the core objective from issue #734.
Linked Issues check ✅ Passed The PR successfully implements all key coding requirements from #734: JSON file-based plugin loading with validation [loader.rs], JSON-RPC harness with stdio support [loader.rs], CLI flags with aliases [cmd_plugin.rs, cmd_bind.rs], in-memory PluginRegistry with indexing [registry.rs], PluginRegistryMemento emission [registry.rs], and PluginLoadFailureMemento with FailureReasonKind [error.rs, types.rs, registry.rs]. Wire types, CID computation, and flag-order preservation all implemented per spec.
Out of Scope Changes check ✅ Passed All code changes are directly scoped to #734 requirements: new provekit-plugin-loader crate, CLI plumbing in cmd_plugin/cmd_bind, attestation/catalog updates reflecting wire-shape changes, Maven config fix for conformance, and integration tests. No unrelated refactoring or feature creep detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/734-plugin-loader-skeleton

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@TSavo TSavo changed the base branch from spec/plugin-protocol to main May 12, 2026 19:42
Implements §3 (file interface), §4 (JSON-RPC stdio interface), §6
(content-addressing), §7 (CLI flag conventions), §8 (error model), §9
(registry semantics) of the plugin-protocol spec (PR #740).

The runtime engine that makes sugar dicts, loss functions, and future
plugin kinds loadable as content-addressed JSON files or JSON-RPC
sidecars.

New crate: provekit-plugin-loader
  - PluginMemento + PluginEnvelope + PluginHeader + PluginMetadata (§1)
  - PluginLoadFailureMemento + FailureReasonKind (§8.1)
  - load_plugin_from_file (§3): parse, shape-validate, CID verify
  - load_plugin_from_rpc (§4): stdio spawn + JSON-RPC describe dispatch
  - compute_plugin_cid (§6.1): JCS over header-without-cid, blake3-512
  - compute_failure_cid (§8.3): JCS over failure header, blake3-512
  - PluginRegistry: BTreeMap<(kind, cid)>; register, lookup, by_kind
  - PluginRegistryMemento + compute_registry_cid (§9.1 + §9.3)
  - mint_failure_memento convenience function
  - stub_rpc_server binary: minimal stdio JSON-RPC sidecar for tests

CLI plumbing (provekit-cli):
  - cmd_plugin.rs: PluginFlags struct + build_registry function
  - Flags: --plugin, --sugar, --loss-fn, --lifter, --no-default-plugins,
    --no-default-plugin, --strict-plugins, --plugin-registry-out
  - BindArgs gains #[command(flatten)] pub plugins: PluginFlags
  - run() seals registry before pipeline work; logs CID prefix

24 tests (16 unit + 8 integration):
  - Pinned CID round-trip for file fixture (byte-stability)
  - CID-delivery-independence for file vs RPC paths
  - Registry (kind, cid) lookup, deduplication, by_kind, emit_memento
  - PluginLoadFailureMemento for missing file (deterministic CID)
  - stdio RPC load via stub_rpc_server binary

No concrete plugins in this PR. Spring sugar (#735), comment sugar
(#736), JUnit sugar (#737), default loss-function (#738), and demo
(#739) follow as separate PRs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@TSavo TSavo force-pushed the feat/734-plugin-loader-skeleton branch from bcc6a51 to 8c665c2 Compare May 12, 2026 19:43
The plugin loader skeleton (PR #758) added a new crate and modified
implementations/rust/Cargo.toml + provekit-cli/Cargo.toml + cmd_bind.rs +
main.rs. These source-byte changes propagated into spec-CID recomputation
via the catalog-verify tool.

This commit re-runs recompute-spec-cids --write to update the stored
CIDs that reflect the new source bytes. No semantic content changes;
only CID values updated to track the actual source bytes.

Two CIDs updated:
- agent-plugin-protocol
- lift-plugin-protocol

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@TSavo
Copy link
Copy Markdown
Owner Author

TSavo commented May 12, 2026

Catalog-verify gate fixed. Commit 86583b0 pushed to this branch.

The recompute-spec-cids --write pass updated exactly 2 CID values in protocol/specs/2026-04-30-protocol-catalog.json:

  • agent-plugin-protocol
  • lift-plugin-protocol

No semantic content changes -- keys, structure, and all other 26 spec CID values are unchanged. cargo run -- --verify exits clean (no "refusing to write" message). CCG should re-run green.

@TSavo
Copy link
Copy Markdown
Owner Author

TSavo commented May 12, 2026

Review: REQUEST CHANGES

Worktree built clean (cargo check -p provekit-plugin-loader finishes; workspace check passes with only pre-existing provekit-lsp dead-code warnings). 24/24 tests pass (16 unit + 8 integration). The crate is well-organized, the type derivation is sound, and the §8 LoadErrorFailureReasonKind mapping is 1:1. But four normative breaches against protocol/specs/2026-05-12-plugin-protocol.md block the merge under Supra omnia, rectum.

Blockers

1. §9.1 load_order wire shape — federation killer (HIGH).
Spec mandates load_order: [* { kind: plugin-kind, cid: cid, source: tstr }]. Implementation (registry.rs:46) types it as Vec<String> and emits a flat list of CIDs. Empirical probe output from emit_registry_memento:

"load_order": ["blake3-512:zzzz","blake3-512:aaaa","blake3-512:mmmm"]

The source field — the verbatim CLI flag value — is dropped entirely. §9.4 audit-replay ("a verifier can re-derive any output by replaying the exact plugin set the run used") cannot be satisfied without it. Worse: this Vec shape is what compute_registry_cid hashes (cid.rs:106-110), so every registry CID this loader emits will diverge from any spec-conformant implementation's CID for the same inputs.

2. §9.1 loaded ordering invariant violated (HIGH).
Spec says loaded is the same set as load_order "sorted by cid ascending" (§9.1 normative). Implementation (registry.rs:167-171) builds loaded from self.load_order.iter() directly — insertion order, no sort. Same empirical probe shows loaded = ["zzzz","aaaa","mmmm"] where a spec-conformant impl would produce ["aaaa","mmmm","zzzz"]. This field is also part of the §9.3 CID input; same federation consequence as #1.

3. §3.1 alias --loss-function rejected (HIGH).
Spec §3.1 lists the canonical alias as --loss-function <source>. Implementation only accepts --loss-fn:

$ provekit bind --loss-function foo.json
error: unexpected argument '--loss-function' found
  tip: a similar argument exists: '--loss-fn'

Plain breach of the §3.1 alias table. The remediation is one line: add #[arg(long = "loss-function", ...)] (keep --loss-fn as a non-spec convenience if desired, but --loss-function MUST work).

4. §3.2 flag-order preservation violated (MEDIUM-HIGH).
Spec §3.2: "CLI flag ORDER is preserved through to the registry's load_order array... Order MUST be deterministic across runs given identical argv." Implementation (cmd_plugin.rs:97-119) processes self.plugins first, then self.sugar, then self.loss_fn, then self.lifter — losing interleaved order. For --plugin a --sugar b --plugin c, the emitted order is [a, c, b], not [a, b, c]. The author's comment at L105-106 acknowledges this choice. Spec doesn't permit it; tie-breaks per sugar-dict-memento.md §4.4 ("later wins") will be wrong.

Non-blocking but must-fix before #735-#738 land

  • §6.2 delivery-independence test is a non-test. tests/integration.rs::rpc_stdio_registry_cid_matches_file_load_when_payload_identical admits in its own comment that the stub emits a different payload, so it can never compare equality. Recommended fix: have the stub bind its payload deterministically to a value that matches a fixture file (write the same content/critical/kind/protocol_versions/provenance_cid/schemaVersion/version), then assert_eq!(file_cid, rpc_cid). The whole §6.2 invariant currently sits on type-system + JCS canonicalizer trust, not on a passing assertion.

  • --no-default-plugins / --no-default-plugin <kind> are parsed but never consulted in build_registry. Vacuously correct today (no built-ins registered), but if ## Sugar #1: Spring (Java) — JSON file #735-## Loss-fn #1: default lexicographic-preorder — JSON file #738 land before this is wired, the flags become non-functional in production. Add a register_builtin filter loop in build_registry keyed off self.no_default_plugins and self.no_default_plugin.contains(&kind).

  • sealed_at hardcoded (cmd_bind.rs:147: "2026-05-12T00:00:00.000Z"). Every provekit bind invocation produces the same registry CID; chrono::Utc::now() is in the TODO already. Must be wired before this binary ships outputs that other consumers cite.

What's solid

  • §6.1 CID input — alphabetical JCS key order, cid correctly elided, protocol_versions sorted ascending. The cid_elides_cid_field and protocol_versions_sort_is_applied unit tests are exactly the right shape and pin the byte-stability claim.
  • §8.1 + §8.3: FailureReasonKind enum is complete and matches the spec verbatim; compute_failure_cid JCS input matches §8.3 exactly.
  • §9.2 dedup: silent no-op on same (kind, cid); correctly returns Ok(false) to distinguish from a true insert.
  • The §4 stdio RPC path is well-scoped: spawns the subprocess, sends one provekit.plugin.describe, validates the response, runs the same parse_and_validate path the file loader uses (so CID verification is shared). Type-level federation between file and RPC delivery is correctly modeled even if the integration test under-asserts it.
  • 24/24 tests pass cleanly on the cherry-picked branch.

Path to merge

Fix #1, #2, #3, #4 above; convert the --loss-function rejection into a passing test; replace the rpc-vs-file CID equality assertion with one that actually verifies the §6.2 invariant. The skeleton's framing doesn't excuse the wire-shape and CLI-alias breaches — every downstream PR will harden them. Once those four are fixed, this is a clean MERGE.

— Reviewed at commit 8c665c2.

…eview

Blockers:
  B1 §9.1 load_order wire shape: Vec<String> -> Vec<{kind,cid,source}>;
     loaded also fixed from Vec<String> to Vec<{kind,cid}> per §9.1 CDDL.
     Registry CIDs now byte-compatible with any spec-conformant loader.
     Added LoadOrderEntry + LoadedEntry types in types.rs; updated
     compute_registry_cid to hash the new object-array shapes.
  B2 §9.1 loaded ordering: sorted by cid ascending per spec; same in
     §9.3 CID input. PluginRegistry::emit_registry_memento now sorts
     loaded entries. Added loaded_is_sorted_by_cid test.
  B3 §3.1 --loss-function alias: added as spec-canonical name (primary),
     --loss-fn retained as ergonomic short alias. Implemented via manual
     clap::Args + FromArgMatches replacing the #[derive(Parser)] that
     could not support B4.
  B4 §3.2 flag-order preservation: manual FromArgMatches uses
     ArgMatches::indices_of to recover true interleaved argv order for
     --plugin / --sugar / --loss-function / --lifter. Eliminates the
     two-pass ordering bug. PluginFlags.ordered field records the
     correct insertion-order sequence for build_registry.

Nits:
  N1 §6.2 delivery-independence test: stub RPC server now emits
     byte-identical JCS payload to tests/fixtures/dummy-sugar.json.
     rpc_stdio_registry_cid_matches_file_load_when_payload_identical
     now asserts CID(file) == CID(rpc) == pinned value.
  N2 --no-default-plugins / --no-default-plugin <kind>: both flags are
     parsed and consulted in build_registry. v0 ships zero default
     plugins so flags are no-ops; the wire surface is preserved for
     when defaults arrive.
  N3 sealed_at: use chrono::Utc::now() for real ISO8601 timestamp in
     cmd_bind.rs. Added chrono 0.4 dep to provekit-cli Cargo.toml.

All 25/25 tests pass (17 unit + 8 integration). cargo check workspace
clean. catalog-verify exit 0 (spec files untouched).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@TSavo
Copy link
Copy Markdown
Owner Author

TSavo commented May 12, 2026

fix: four spec-correctness blockers + three nits addressed at b673fac. Ready for re-review.

B1 §9.1 load_order wire shape: Vec<String> -> Vec<{kind,cid,source}>; loaded also fixed from Vec<String> to Vec<{kind,cid}> per §9.1 CDDL. LoadOrderEntry + LoadedEntry types added. compute_registry_cid updated to hash the new object-array shapes.

B2 §9.1 loaded ordering: sorted by cid ascending; same in §9.3 CID input. New loaded_is_sorted_by_cid test added.

B3 §3.1 --loss-function alias: added as spec-canonical primary name; --loss-fn retained as ergonomic short alias.

B4 §3.2 flag-order preservation: manual clap::Args + FromArgMatches impl uses ArgMatches::indices_of to recover true interleaved argv order across --plugin / --sugar / --loss-function / --lifter. Two-pass ordering bug eliminated.

N1 §6.2 delivery-independence: stub RPC server now emits byte-identical payload to tests/fixtures/dummy-sugar.json. Test now asserts CID(file) == CID(rpc) == pinned value.

N2 --no-default-plugins / --no-default-plugin <kind>: both flags parsed and consulted in build_registry. No-ops in v0 (zero default plugins); wire surface preserved.

N3 sealed_at: chrono::Utc::now() replaces hardcoded timestamp in cmd_bind.rs.

All 25/25 tests pass. cargo check workspace clean. catalog-verify exit 0.

@TSavo
Copy link
Copy Markdown
Owner Author

TSavo commented May 12, 2026

Re-review verdict: MERGE-WITH-NITS

Re-reviewed at b673fac. All four blockers and all three nits land correctly. The substance is right — wire shape matches §9.1, JCS ordering is right, B4's indices_of approach correctly recovers true argv interleaving, delivery-independence test now exercises the real invariant.

Verified

  • B1LoadOrderEntry {cid, kind, source} + LoadedEntry {cid, kind} in types.rs. compute_registry_cid in cid.rs hashes the object-array shapes with alphabetical JCS key order (cid before kind before source). Pinned fixture CID blake3-512:ad148c5f… re-pinned to new shape; fixture file matches.
  • B2registry.rs::emit_registry_memento does loaded.sort() BEFORE building the header that flows into compute_registry_cid — sort affects the CID, not just display. New loaded_is_sorted_by_cid test (registry.rs:373) feeds CIDs [zzz, aaa, mmm] and asserts loaded == [aaa, mmm, zzz] while load_order == [zzz, aaa, mmm].
  • B3 ✅ Help text shows --loss-function <SOURCE> as primary with --loss-fn noted as short alias. Confirmed via probe:
    • --loss-function foo.jsonloss_fn = ["foo.json"]
    • --loss-fn foo.jsonloss_fn = ["foo.json"]
  • B4 ✅ Manual FromArgMatches::update_from_arg_matches uses matches.indices_of("plugin"|"sugar"|"loss_fn"|"lifter"), zips with values, collects into (argv_index, kind, source, verbatim) tuples, and sort_by_key(idx) to recover true interleaving. --lifter correctly maps to wire kind "lift" (§2.1). Empirically probed (see test gap below).
  • N1stub_rpc_server.rs::fixture_plugin_memento reconstructs the same PluginHeader as the fixture file and computes the CID live; integration test rpc_stdio_registry_cid_matches_file_load_when_payload_identical asserts CID(rpc) == CID(file) == pinned.
  • N2build_registry gates default-plugin registration behind !self.no_default_plugins with a per-kind suppression inner loop. No-ops in v0, wire surface preserved.
  • N3cmd_bind.rs:148: chrono::Utc::now().format("%Y-%m-%dT%H:%M:%S%.3fZ") — correct ISO8601 with millisecond precision.
  • No regressions: §6.1 cid-elision + protocol_versions sort, §8.3 failure CID, §9.2 dedup, §4 stdio RPC all intact.
  • Test count: 25/25 pass (17 unit + 8 integration). cargo check --workspace clean. cargo run --release --manifest-path tools/recompute-spec-cids/Cargo.toml -- --verify exits 0.

Nits (cleanup, NOT merge-blocking)

N4: B4 has no automated regression test. The most substantive piece of this fix — interleaved argv-order recovery — ships with zero pinned coverage. The 25/25 includes nothing that asserts the interleaving invariant; only this re-review exercised it. Suggested paste-in for cmd_plugin.rs (verified to pass against b673fac):

#[cfg(test)]
mod b4_tests {
    use super::*;
    use clap::{ArgMatches, Command, FromArgMatches};

    fn parse(argv: &[&str]) -> PluginFlags {
        let cmd = PluginFlags::augment_args(Command::new("probe"));
        let m: ArgMatches = cmd.try_get_matches_from(argv).unwrap();
        PluginFlags::from_arg_matches(&m).unwrap()
    }

    #[test]
    fn b3_loss_function_primary_name_accepted() {
        let f = parse(&["probe", "--loss-function", "foo.json"]);
        assert_eq!(f.loss_fn, vec!["foo.json".to_string()]);
    }

    #[test]
    fn b3_loss_fn_alias_still_accepted() {
        let f = parse(&["probe", "--loss-fn", "foo.json"]);
        assert_eq!(f.loss_fn, vec!["foo.json".to_string()]);
    }

    #[test]
    fn b4_interleaved_order_preserved() {
        let f = parse(&[
            "probe",
            "--plugin", "sugar:a.json",
            "--sugar", "b.json",
            "--plugin", "sugar:c.json",
            "--loss-function", "d.json",
            "--plugin", "loss-function:e.json",
        ]);
        let kinds: Vec<&str> = f.ordered.iter().map(|(k,_,_)| k.as_str()).collect();
        let sources: Vec<&str> = f.ordered.iter().map(|(_,s,_)| s.as_str()).collect();
        assert_eq!(kinds, vec!["sugar","sugar","sugar","loss-function","loss-function"]);
        assert_eq!(sources, vec!["a.json","b.json","c.json","d.json","e.json"]);
    }

    #[test]
    fn b4_lifter_uses_wire_kind_lift() {
        let f = parse(&["probe", "--lifter", "x.json"]);
        assert_eq!(f.ordered.len(), 1);
        assert_eq!(f.ordered[0].0, "lift");
    }
}

Requires making ordered and (plugins/sugar/loss_fn/lifter) pub(crate) or adding a pub fn ordered(&self) -> &[(String, String, String)] accessor. The pub(crate) route is the small-change path.

N5: dead-code branch. cmd_plugin.rs:320if let Err(dup_err) = registry.register(...) is unreachable because register returns Ok(false) on dedup, never Err. Pre-existing from the original PR, not a regression of this fix. Either remove the branch or change register's signature so it can actually error on conflict.

N6: stray hardcoded timestamp. cmd_bind.rs:628 still uses "2026-05-12T00:00:00.000Z" for MintContractArgs.produced_at. N3's scope was registry sealed_at only, which is the right scope cut for this PR, but flagging this separately so it's not lost — likely wants chrono::Utc::now() in a follow-up.

Verdict

Ship it. The B4 mechanics are correct under empirical probing; the missing test is a real gap but a follow-up tightening, not a merge blocker — the spec compliance and wire shape are right. N5 and N6 are pre-existing scope items.

Re-reviewed in worktree /private/tmp/pk-758-rr2 at HEAD b673facc.

🤖 Generated with Claude Code

TSavo and others added 2 commits May 12, 2026 13:39
The blockers fix at b673fac changed the plugin loader wire shape per
spec §9.1 (LoadOrderEntry/LoadedEntry). That CID shift propagated into
the contract set referenced by ACCEPTED_LIFT_PLUGIN_PROTOCOL_CONTRACT_SET_CID
in provekit-self-contracts, which cross-kit-conformance pins.

Regenerated CID: updated to match the actual contract set bytes
post-blockers-fix. Cargo.lock churn is mechanical (cargo rebuild).
No semantic drift.
…e Maven probe

provekit-ir is local-source-only and is not published to Maven Central.
java_classpath() was running `mvn package` which writes to target/ only;
the subsequent `dependency:build-classpath` on provekit-claim-envelope
then tried to resolve provekit-ir as a declared dep and hit Maven Central,
where it is not published, producing a cached-resolution failure on CI.

Fix: change `package` to `install` so provekit-ir lands in ~/.m2 before
the classpath probe runs. Matches the precedent at Makefile:216 (build-java
uses `mvn install -am` for exactly this reason).

Also refresh self-contract attestations for csharp/go/java/ruby/rust to
reflect the kit contract-set CIDs that are live in this branch.

Verified: make cross-kit-conformance exits 0 with a clean ~/.m2/com/provekit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@TSavo
Copy link
Copy Markdown
Owner Author

TSavo commented May 12, 2026

fix(357cdc3): java_classpath() was calling mvn package which writes only to target/; the subsequent dependency:build-classpath then tried to resolve provekit-ir from Maven Central (not published there) and hit a cached-resolution failure on fresh CI runners. Changed to mvn install so provekit-ir lands in ~/.m2 first, matching the precedent at Makefile:216. Also refreshed self-contract attestations that were already consistent in the branch. make cross-kit-conformance exits 0 with a clean ~/.m2/com/provekit.

@TSavo
Copy link
Copy Markdown
Owner Author

TSavo commented May 12, 2026

cross-kit-conformance fixtures are clean. Both blockers already landed on this branch:

  • e8e6c0c: updated ACCEPTED_LIFT_PLUGIN_PROTOCOL_CONTRACT_SET_CID to match post-blockers wire shape
  • 357cdc3: regenerated self-contract attestations (csharp/go/java/ruby/rust) + fixed Maven classpath ordering

Local verification: make cross-kit-conformance exits 0, make catalog-verify exits 0, cargo test -p provekit-plugin-loader 8/8 pass.

…dditions

#758 added new self-contracts (c1_holds_on_legacy_protocol_version_in_
migration_window, etc.). The pinned contractSetCid values in
mint_kit_integration.rs referenced the pre-additions contract set and
diverged.

Updated pinned values to match the actual current contract set bytes.
No semantic content changes; only the test pins reflect the substrate's
current state.
@TSavo
Copy link
Copy Markdown
Owner Author

TSavo commented May 12, 2026

fix: regenerated pinned kit contractSetCids for the plugin-loader's new self-contracts. CCG should re-run green.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
implementations/rust/provekit-plugin-loader/src/loader.rs (1)

98-104: ⚖️ Poor tradeoff

Consider documenting command-line parsing limitations.

The stdio: command parsing at lines 98-104 uses splitn(2, ' ') followed by split_whitespace(). This approach won't handle quoted arguments, escaped spaces, or shell special characters. For example, stdio:my-plugin --arg "value with spaces" would split incorrectly.

This is acceptable for the current test-focused implementation, but worth documenting as a known limitation if stdio: sources are intended for production use.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@implementations/rust/provekit-plugin-loader/src/loader.rs` around lines 98 -
104, Document that the command-line parsing in the stdio loader is simplistic:
the code that splits cmd_str using splitn(2, ' ') and then split_whitespace()
(variables/expressions: cmd_str, parts, bin, rest_args, args, splitn,
split_whitespace) does not support quoted arguments, escaped spaces, or shell
metacharacters, and therefore will misparse inputs like `stdio:my-plugin --arg
"value with spaces"`; add a concise note in the loader.rs comments (near the
parsing block) describing this limitation and recommending a more robust parser
(e.g., a shell-like tokenizer) if stdio sources are ever used in production.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@implementations/rust/provekit-cli/src/cmd_plugin.rs`:
- Around line 358-367: The block that serializes and writes the registry uses
serde_json::to_string_pretty(&memento).expect(...) and logs write failures
instead of returning them; change this to propagate errors back to the caller:
replace the .expect(...) with using the ? operator (or map_err/Context to attach
a descriptive message) when calling serde_json::to_string_pretty(&memento) and
likewise change the std::fs::write(out_path, json).unwrap_or_else(...) to a ?
(or map_err/Context) so the function returns an Err on failure (include
descriptive context like "failed to serialize plugin registry" and "failed to
write plugin registry to {out_path}"). Ensure the function signature returns a
Result so these ?-propagated errors compile and bubble up to the caller instead
of panicking or only logging.

In `@implementations/rust/provekit-plugin-loader/src/cid.rs`:
- Around line 71-76: The serde_json::Value::Number branch currently coerce
non-i64 numbers to strings (Value::string(n.to_string())), which silently
changes JSON types; instead make the conversion explicit-failing: in the
function that converts serde_json::Value to the canonicalizer Value (the branch
handling serde_json::Value::Number), keep Value::integer(i) for n.as_i64() but
remove the Value::string fallback and return a validation error for any number
that is not representable as i64 (e.g., Err(Error::new("unsupported JSON number:
not i64"))). Update the conversion function signature to return Result<...>
(e.g., Result<Value, ValidationError>) and propagate/handle that error at the
callers so unsupported numeric forms are rejected at validation time rather than
coerced into strings.

In `@implementations/rust/provekit-plugin-loader/src/loader.rs`:
- Around line 97-125: In load_plugin_from_stdio_rpc replace the unconditional
panic from serde_json::to_vec(...).expect("request serialization") with proper
error handling: call serde_json::to_vec(&request) and map any Err into a
LoadError::RpcError (include a descriptive detail string mentioning the
serialization error and the original error), returning that Err early; then
proceed using the produced request_bytes. This change should reference the
serde_json::to_vec call, the request_bytes variable, and return
LoadError::RpcError on failure.

---

Nitpick comments:
In `@implementations/rust/provekit-plugin-loader/src/loader.rs`:
- Around line 98-104: Document that the command-line parsing in the stdio loader
is simplistic: the code that splits cmd_str using splitn(2, ' ') and then
split_whitespace() (variables/expressions: cmd_str, parts, bin, rest_args, args,
splitn, split_whitespace) does not support quoted arguments, escaped spaces, or
shell metacharacters, and therefore will misparse inputs like `stdio:my-plugin
--arg "value with spaces"`; add a concise note in the loader.rs comments (near
the parsing block) describing this limitation and recommending a more robust
parser (e.g., a shell-like tokenizer) if stdio sources are ever used in
production.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 86a8179a-37b1-48f3-8e4c-90eeabc33b23

📥 Commits

Reviewing files that changed from the base of the PR and between b0ef745 and 76d4810.

⛔ Files ignored due to path filters (2)
  • implementations/rust/Cargo.lock is excluded by !**/*.lock
  • tools/cross-kit-conformance/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (24)
  • .provekit/self-contracts-attestations/csharp.json
  • .provekit/self-contracts-attestations/go.json
  • .provekit/self-contracts-attestations/java.json
  • .provekit/self-contracts-attestations/ruby.json
  • .provekit/self-contracts-attestations/rust.json
  • implementations/rust/Cargo.toml
  • implementations/rust/provekit-cli/Cargo.toml
  • implementations/rust/provekit-cli/src/cmd_bind.rs
  • implementations/rust/provekit-cli/src/cmd_plugin.rs
  • implementations/rust/provekit-cli/src/main.rs
  • implementations/rust/provekit-cli/tests/mint_kit_integration.rs
  • implementations/rust/provekit-plugin-loader/Cargo.toml
  • implementations/rust/provekit-plugin-loader/src/bin/stub_rpc_server.rs
  • implementations/rust/provekit-plugin-loader/src/cid.rs
  • implementations/rust/provekit-plugin-loader/src/error.rs
  • implementations/rust/provekit-plugin-loader/src/lib.rs
  • implementations/rust/provekit-plugin-loader/src/loader.rs
  • implementations/rust/provekit-plugin-loader/src/registry.rs
  • implementations/rust/provekit-plugin-loader/src/types.rs
  • implementations/rust/provekit-plugin-loader/tests/fixtures/dummy-sugar.json
  • implementations/rust/provekit-plugin-loader/tests/integration.rs
  • implementations/rust/provekit-self-contracts/src/lib.rs
  • protocol/specs/2026-04-30-protocol-catalog.json
  • tools/cross-kit-conformance/src/lib.rs

Comment on lines +358 to +367
if let Some(ref out_path) = self.plugin_registry_out {
let json =
serde_json::to_string_pretty(&memento).expect("registry memento serialization");
std::fs::write(out_path, json).unwrap_or_else(|e| {
eprintln!(
"plugin-loader: could not write registry to {}: {e}",
out_path.display()
);
});
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Consider propagating registry write errors.

The serde_json::to_string_pretty call at line 360 uses .expect(), which will panic if serialization fails. While unlikely for well-formed data structures, defensive error handling would be safer.

Additionally, the file write failure at line 361 is logged but not propagated to the caller. If the user explicitly requested --plugin-registry-out, they likely expect either the file to be written or an error returned.

🛡️ Proposed fix to propagate write errors
         // Write registry memento to disk if requested (§7).
         if let Some(ref out_path) = self.plugin_registry_out {
-            let json =
-                serde_json::to_string_pretty(&memento).expect("registry memento serialization");
-            std::fs::write(out_path, json).unwrap_or_else(|e| {
-                eprintln!(
-                    "plugin-loader: could not write registry to {}: {e}",
-                    out_path.display()
-                );
-            });
+            let json = serde_json::to_string_pretty(&memento).map_err(|e| {
+                PluginLoadRefusal {
+                    failure: mint_failure_memento(
+                        "--plugin-registry-out",
+                        "registry",
+                        &LoadError::ValidationError {
+                            detail: format!("registry serialization failed: {e}"),
+                        },
+                        sealed_at,
+                    ),
+                    source: format!("--plugin-registry-out={}", out_path.display()),
+                }
+            })?;
+            std::fs::write(out_path, json).map_err(|e| {
+                PluginLoadRefusal {
+                    failure: mint_failure_memento(
+                        "--plugin-registry-out",
+                        "registry",
+                        &LoadError::ValidationError {
+                            detail: format!("failed to write {}: {e}", out_path.display()),
+                        },
+                        sealed_at,
+                    ),
+                    source: format!("--plugin-registry-out={}", out_path.display()),
+                }
+            })?;
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@implementations/rust/provekit-cli/src/cmd_plugin.rs` around lines 358 - 367,
The block that serializes and writes the registry uses
serde_json::to_string_pretty(&memento).expect(...) and logs write failures
instead of returning them; change this to propagate errors back to the caller:
replace the .expect(...) with using the ? operator (or map_err/Context to attach
a descriptive message) when calling serde_json::to_string_pretty(&memento) and
likewise change the std::fs::write(out_path, json).unwrap_or_else(...) to a ?
(or map_err/Context) so the function returns an Err on failure (include
descriptive context like "failed to serialize plugin registry" and "failed to
write plugin registry to {out_path}"). Ensure the function signature returns a
Result so these ?-propagated errors compile and bubble up to the caller instead
of panicking or only logging.

Comment on lines +71 to +76
serde_json::Value::Number(n) => {
if let Some(i) = n.as_i64() {
Value::integer(i)
} else {
Value::string(n.to_string())
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Locate canonicalizer Value definition and numeric constructors =="
rg -n --type=rust -C3 'enum\s+Value|fn\s+integer\s*\(|fn\s+number\s*\(|float|double|u64|i128' implementations/rust/provekit-canonicalizer

echo
echo "== Locate current number coercion in plugin loader CID code =="
rg -n --type=rust -C3 'serde_json::Value::Number|as_i64\(|to_string\(\)|Value::string' implementations/rust/provekit-plugin-loader/src/cid.rs

Repository: TSavo/provekit

Length of output: 12098


Avoid coercing JSON numbers into strings during CID input construction.

Line 75 silently converts non-i64 numbers to strings, changing JSON value type and affecting CID computation. The canonicalizer's Value type supports only i64 integers, not arbitrary precision or floating-point numbers. Rather than type-coercing unsupported numeric forms to strings, reject them explicitly at validation time so mismatched CIDs surface as errors instead of propagating silently.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@implementations/rust/provekit-plugin-loader/src/cid.rs` around lines 71 - 76,
The serde_json::Value::Number branch currently coerce non-i64 numbers to strings
(Value::string(n.to_string())), which silently changes JSON types; instead make
the conversion explicit-failing: in the function that converts serde_json::Value
to the canonicalizer Value (the branch handling serde_json::Value::Number), keep
Value::integer(i) for n.as_i64() but remove the Value::string fallback and
return a validation error for any number that is not representable as i64 (e.g.,
Err(Error::new("unsupported JSON number: not i64"))). Update the conversion
function signature to return Result<...> (e.g., Result<Value, ValidationError>)
and propagate/handle that error at the callers so unsupported numeric forms are
rejected at validation time rather than coerced into strings.

Comment on lines +97 to +125
fn load_plugin_from_stdio_rpc(cmd_str: &str) -> Result<PluginMemento, LoadError> {
let parts: Vec<&str> = cmd_str.splitn(2, ' ').collect();
let (bin, rest_args) = (parts[0], parts.get(1).copied().unwrap_or(""));
let args: Vec<&str> = if rest_args.is_empty() {
vec![]
} else {
rest_args.split_whitespace().collect()
};

let mut child = Command::new(bin)
.args(&args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::null())
.spawn()
.map_err(|e| LoadError::RpcError {
detail: format!("failed to spawn stdio plugin `{bin}`: {e}"),
})?;

// Build request (§4.2.1).
let request = serde_json::json!({
"jsonrpc": "2.0",
"id": 1,
"method": "provekit.plugin.describe",
"params": {
"runtime_protocol_versions": RUNTIME_PROTOCOL_VERSIONS
}
});
let request_bytes = serde_json::to_vec(&request).expect("request serialization");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace .expect() with proper error handling.

Line 125 uses .expect("request serialization") which will panic if serde_json::to_vec fails. While serialization of a json! macro result should never fail, defensive error handling is safer.

🛡️ Proposed fix
     let request = serde_json::json!({
         "jsonrpc": "2.0",
         "id": 1,
         "method": "provekit.plugin.describe",
         "params": {
             "runtime_protocol_versions": RUNTIME_PROTOCOL_VERSIONS
         }
     });
-    let request_bytes = serde_json::to_vec(&request).expect("request serialization");
+    let request_bytes = serde_json::to_vec(&request).map_err(|e| LoadError::RpcError {
+        detail: format!("failed to serialize JSON-RPC request: {e}"),
+    })?;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@implementations/rust/provekit-plugin-loader/src/loader.rs` around lines 97 -
125, In load_plugin_from_stdio_rpc replace the unconditional panic from
serde_json::to_vec(...).expect("request serialization") with proper error
handling: call serde_json::to_vec(&request) and map any Err into a
LoadError::RpcError (include a descriptive detail string mentioning the
serialization error and the original error), returning that Err early; then
proceed using the produced request_bytes. This change should reference the
serde_json::to_vec call, the request_bytes variable, and return
LoadError::RpcError on failure.

…rent value

The prior pin-fix updated GO_CONTRACT_SET_CID but skipped the rust pin
because the rust mint-self-contracts binary hits a skip path on macOS,
making the local test appear to pass. On Linux CI it actually runs and
catches the drift.

Updated to the CID emitted by Linux CI (from CCG run 25764503850 failure
message). Both Linux and macOS pins updated to the same value per the
existing 'macOS currently emits the same' comment.

  Old: blake3-512:eb9979cc...
  New: blake3-512:3b41145b...

No semantic change; tracking actual current contract set bytes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

## Impl: plugin loader skeleton (JSON file + JSON-RPC harness + CLI + registry)

2 participants