feat(context): introduce GroupRequest and ContextGroupId types for group management#2043
feat(context): introduce GroupRequest and ContextGroupId types for group management#2043
Conversation
There was a problem hiding this comment.
🤖 AI Code Reviewer
Reviewed by 3 agents | Quality score: 100% | Review time: 167.3s
💡 1 suggestions. See inline comments.
🤖 Generated by AI Code Reviewer | Review ID: review-3e67acf7
…isterFromGroup structure
There was a problem hiding this comment.
🤖 AI Code Reviewer
Reviewed by 3 agents | Quality score: 100% | Review time: 227.1s
💡 3 suggestions. See inline comments.
🤖 Generated by AI Code Reviewer | Review ID: review-078e5b50
There was a problem hiding this comment.
🤖 AI Code Reviewer
Reviewed by 3 agents | Quality score: 100% | Review time: 203.4s
💡 2 suggestions, 📝 1 nitpicks. See inline comments.
🤖 Generated by AI Code Reviewer | Review ID: review-86d4a70f
There was a problem hiding this comment.
🤖 AI Code Reviewer
Reviewed by 3 agents | Quality score: 100% | Review time: 197.8s
🟡 2 warnings, 💡 2 suggestions. See inline comments.
🤖 Generated by AI Code Reviewer | Review ID: review-04819256
…anced group management
…etaValue, GroupUpgradeValue, and GroupUpgradeStatus structures for enhanced group upgrade management
There was a problem hiding this comment.
🤖 AI Code Reviewer
Reviewed by 3 agents | Quality score: 89% | Review time: 319.2s
🟡 2 warnings, 💡 4 suggestions. See inline comments.
🤖 Generated by AI Code Reviewer | Review ID: review-f10665bd
Each test starts a real TCP mock server, asserts the client sends the correct HTTP verb + path, and round-trips the response body through serde. Auth is bypassed by setting node_name=None in ConnectionInfo. Also resolves PR review thread PRRT_kwDOLIG5Is50218T (comment 2946573387). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…dtrips Replace fragile borsh serialize/deserialize roundtrips for PublicKey↔SignerId and ContextGroupId conversions with direct From<[u8; 32]> and to_bytes() accessors now that SignerId exposes them. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…assertions Replace scattered unsafe pointer casts from `[SignerId]` to `[Repr<SignerId>]` with a safe `Repr::slice_from_inner` helper that uses inline `const` assertions to enforce the `#[repr(transparent)]` layout invariant at compile time per monomorphization, turning a silent UB risk into a compile error. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
🤖 AI Code Reviewer
Reviewed by 3 agents | Quality score: 93% | Review time: 332.1s
🟡 1 warnings, 💡 4 suggestions. See inline comments.
🤖 Generated by AI Code Reviewer | Review ID: review-b85d5844
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Organizes the 27 group management methods into a dedicated sub-module (`src/client/group.rs`) per the module structure convention, keeping `client.rs` focused on core context/application API methods. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
There was a problem hiding this comment.
🤖 AI Code Reviewer
Reviewed by 3 agents | Quality score: 100% | Review time: 541.4s
💡 4 suggestions. See inline comments.
🤖 Generated by AI Code Reviewer | Review ID: review-2fcad253
store_group_signing_key was called unconditionally with the requester's public key but the node's private key, producing an invalid (requester_pk → node_sk) mapping whenever requester != node_pk. In create_group_invitation this caused signature verification to fail on the joiner side (inviter_identity=requester_pk signed with node_sk). Add a requester == node_pk equality guard before the store call in both create_group_invitation and upgrade_group so the auto-store only fires when the node IS the requester. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add security note to get_key_public_key clarifying key_id must come from a verified JWT token, not untrusted caller input - Replace unreachable!() with descriptive unimplemented!() messages in NoopAuth/NoopStorage test stubs to aid debugging if called unexpectedly - Replace slice_from_inner unsafe cast in manage_context_allowlist with safe iterator-based Repr::new() mapping to avoid reliance on undocumented repr layout guarantees Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
🤖 AI Code Reviewer
Reviewed by 3 agents | Quality score: 100% | Review time: 370.3s
🟡 1 warnings, 💡 2 suggestions. See inline comments.
🤖 Generated by AI Code Reviewer | Review ID: review-4661abb1
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
- Introduced a new document detailing the Context Group Management feature, which allows users to organize multiple contexts, manage shared memberships, and propagate application upgrades. - Updated the README to include a link to the new documentation.

[core] Implement hierarchical context group management
Description
Implements the full Context Groups feature across
core/crates/, enabling administrators to organize contexts into groups with shared application targets, coordinated upgrades, and membership management. Built across 6 phases on top of thecontext-configcontract types (ContextGroupId,GroupRequest,AppKey).Phase 1 — Storage Foundation
store/src/key/group.rs:GroupMeta(0x20),GroupMember(0x21),GroupContextIndex(0x22),ContextGroupRef(0x23),GroupUpgradeKey(0x24) — all withAsKeyParts/FromKeyPartsimpls and roundtrip testsGroupMetaValue,GroupUpgradeValue,GroupUpgradeStatuswith Borsh serializationprimitives/src/context.rs:UpgradePolicy(Automatic / LazyOnAccess / Coordinated),GroupMemberRole(Admin / Member),GroupInvitationPayloadPhase 2 — Group CRUD + Membership
group_store.rs(~390 LOC): Complete storage helper layer — CRUD for group metadata, members, context indices, and upgrade records with efficient key-only iteration for countingcreate_group,delete_group,add_group_members,remove_group_members,get_group_info,list_group_membersPhase 3 — Context-Group Integration
create_context.rs: Pre-validates group membership + app override; post-creation registers context in group indexdelete_context.rs: Unregisters context from group on deletionlist_group_contexts: New paginated endpoint for listing a group's contextsPhase 4 — Upgrade Propagation
propagate_upgrade(): Async fn that iterates group contexts, callsupdate_application()per context, persists progress after each stepGroupUpgradeStatus::InProgress { total, completed, failed }→Completed { completed_at }POST /upgrade,GET /upgrade/status,POST /upgrade/retryPhase 5 — Advanced Policies + Crash Recovery
execute.rstransparently upgrades stale contexts before method execution whenUpgradePolicy::LazyOnAccessis setContextManager::started()scans forInProgressupgrades and re-spawns propagatorsPhase 6 — Group Invitations + Join Flow
GroupInvitationPayload: Borsh-serialized + base58-encoded invitation token (mirrorsContextInvitationPayloadpattern)invitee_identity: Some) and open (invitee_identity: None) invitation modesPOST /groups/:id/invite,POST /groups/joinPost-implementation fixes (PR review)
propagate_upgradecompleted counter on retry/recovery pathsGroupContextIndexon re-registration, orphaned upgrade records on group deletion,Duration::newpanic on malformed Borsh, switched toValidatedJsonfor upgrade inputcount_group_admins/count_group_contextswithout Vec allocation, added offset/limit toenumerate_group_contexts, batched member cleanup in delete_groupGroupUpgradeValue/GroupUpgradeStatusstore types fromcalimero-context-primitivesAPI boundary — introducedGroupUpgradeInfoand primitives-localGroupUpgradeStatuswithFromconversion implscount_group_members()for efficient member counting, inlined value read inenumerate_in_progress_upgradesto reuse store handleNew API routes
Test plan
cargo check --workspace— compiles cleanlycargo fmt --check— no formatting issuescargo clippy -- -A warnings— no errorscargo test -p calimero-context— 16 tests passcargo test -p calimero-context-primitives— 3 tests passcargo test -p calimero-store— key roundtrip + value serialization tests passmeroctlagainst a runningmerodnodecontracts/repoDocumentation update
N/A — these are internal protocol types. Public API documentation should be added once the full group management feature is shipped end-to-end.
Note
Medium Risk
Adds a large set of new group-management request/response types and client APIs, plus changes to node identity/config serialization; mistakes could break group operations or config compatibility and affect auth-protected admin endpoints.
Overview
Introduces context group management primitives in
calimero-context-configby addingContextGroupId/AppKey,GroupRequest/GroupRequestKind, group invitation payload types, and new group-related query request/response structs.Extends the context-config client to build and send group mutate/query operations (and removes UB
transmutedecodes in favor of safeReprunwrapping), and adds an on-chainExternalGroupClientwith nonce-retry handling for group contract mutations.Expands the HTTP client/admin API surface with a new
groupmodule exposingadmin-api/groups/*methods, addsPATCH/PUT/DELETE-with-body support and better error extraction inConnectionInfo, and updatesdelete_contextto accept an optionalrequesterbody.Updates node configuration identity to a structured
[identity]section that can include an optional group signing identity (GroupIdentityConfig), adds a small auth helper to fetch a stored public key by verifiedkey_id, and updates docs/deps/tests (addswiremocktests for the new client methods, and updatesREADME.mdxlink).Written by Cursor Bugbot for commit b73d448. This will update automatically on new commits. Configure here.