diff --git a/web4-standard/implementation/sdk/tests/test_errors.py b/web4-standard/implementation/sdk/tests/test_errors.py index d5bdf0c..330a08a 100644 --- a/web4-standard/implementation/sdk/tests/test_errors.py +++ b/web4-standard/implementation/sdk/tests/test_errors.py @@ -37,21 +37,26 @@ class TestRegistryCompleteness: """Every ErrorCode must have metadata in the registry.""" - def test_all_24_codes_registered(self): + def test_all_30_codes_registered(self): for code in ErrorCode: meta = get_error_meta(code) assert meta.code == code - def test_exactly_24_codes(self): - assert len(ErrorCode) == 24 + def test_exactly_30_codes(self): + assert len(ErrorCode) == 30 - def test_exactly_6_categories(self): - assert len(ErrorCategory) == 6 + def test_exactly_7_categories(self): + assert len(ErrorCategory) == 7 - def test_4_codes_per_category(self): + def test_codes_per_category(self): + # 6 original categories have 4 codes each; CROSS_SOCIETY has 6 + expected = {cat: 4 for cat in ErrorCategory} + expected[ErrorCategory.CROSS_SOCIETY] = 6 for cat in ErrorCategory: codes = codes_for_category(cat) - assert len(codes) == 4, f"{cat} has {len(codes)} codes, expected 4" + assert len(codes) == expected[cat], ( + f"{cat} has {len(codes)} codes, expected {expected[cat]}" + ) def test_all_codes_have_title(self): for code in ErrorCode: diff --git a/web4-standard/implementation/sdk/tests/test_mcp_cross_society.py b/web4-standard/implementation/sdk/tests/test_mcp_cross_society.py new file mode 100644 index 0000000..8537705 --- /dev/null +++ b/web4-standard/implementation/sdk/tests/test_mcp_cross_society.py @@ -0,0 +1,416 @@ +"""Tests for cross-society MCP types (mcp-protocol.md §7.3–7.6).""" + +from web4.errors import ( + CrossSocietyError, + ErrorCategory, + ErrorCode, + Web4Error, + codes_for_category, + get_error_meta, + make_error, +) +from web4.mcp import ( + CrossSocietyContext, + CrossSocietyInteractionType, + MCPContextResource, + OutcomeClass, + PropagationScope, + ReputationEnvelope, + TrustRequirements, +) + +# ── OutcomeClass Enum ──────────────────────────────────────────── + + +class TestOutcomeClass: + def test_enum_values(self) -> None: + assert OutcomeClass.SUCCESS.value == "success" + assert OutcomeClass.PARTIAL.value == "partial" + assert OutcomeClass.FAILURE.value == "failure" + assert OutcomeClass.VIOLATION.value == "violation" + + def test_enum_count(self) -> None: + assert len(OutcomeClass) == 4 + + def test_string_construction(self) -> None: + assert OutcomeClass("success") is OutcomeClass.SUCCESS + assert OutcomeClass("violation") is OutcomeClass.VIOLATION + + +# ── PropagationScope Enum ──────────────────────────────────────── + + +class TestPropagationScope: + def test_enum_values(self) -> None: + assert PropagationScope.RESPONDING_SOCIETY.value == "responding_society" + assert PropagationScope.CALLER_SOCIETY.value == "caller_society" + assert PropagationScope.BOTH.value == "both" + assert PropagationScope.ENCOMPASSING_SOCIETY.value == "encompassing_society" + + def test_enum_count(self) -> None: + assert len(PropagationScope) == 4 + + +# ── CrossSocietyInteractionType Enum ───────────────────────────── + + +class TestCrossSocietyInteractionType: + def test_enum_values(self) -> None: + assert CrossSocietyInteractionType.FIRST_CONTACT.value == "first_contact" + assert CrossSocietyInteractionType.ESTABLISHED.value == "established" + assert CrossSocietyInteractionType.FEDERATED.value == "federated" + + def test_enum_count(self) -> None: + assert len(CrossSocietyInteractionType) == 3 + + +# ── CrossSocietyContext ────────────────────────────────────────── + + +class TestCrossSocietyContext: + def test_minimal_construction(self) -> None: + ctx = CrossSocietyContext( + sender_lct="lct:web4:entity:alice", + sender_society="lct:web4:society:A", + responding_society="lct:web4:society:B", + ) + assert ctx.sender_lct == "lct:web4:entity:alice" + assert ctx.sender_society == "lct:web4:society:A" + assert ctx.responding_society == "lct:web4:society:B" + assert ctx.interaction_type is CrossSocietyInteractionType.ESTABLISHED + + def test_full_construction(self) -> None: + ctx = CrossSocietyContext( + sender_lct="lct:web4:entity:alice", + sender_society="lct:web4:society:A", + responding_society="lct:web4:society:B", + interaction_type=CrossSocietyInteractionType.FIRST_CONTACT, + sender_role="web4:role:resource_consumer", + responding_role_expected="web4:role:resource_provider", + applicable_law_oracle="lct:web4:society:A:law-oracle", + exchange_agreement_hash="sha256:abc123", + atp_settlement_currency="ATP-A", + atp_settlement_amount=100, + atp_settlement_exchange_rate={"rate": 1.5, "referent": "compute_hour"}, + mrh_depth=2, + law_hash="sha256:law123", + ) + assert ctx.interaction_type is CrossSocietyInteractionType.FIRST_CONTACT + assert ctx.atp_settlement_amount == 100 + + def test_to_dict_minimal(self) -> None: + ctx = CrossSocietyContext( + sender_lct="lct:alice", + sender_society="lct:society:A", + responding_society="lct:society:B", + ) + d = ctx.to_dict() + assert d["sender_lct"] == "lct:alice" + assert d["sender_society"] == "lct:society:A" + assert d["responding_society"] == "lct:society:B" + assert d["interaction_type"] == "established" + assert "cross_society" in d + assert d["cross_society"]["interaction_type"] == "established" + assert d["mrh_depth"] == 1 + + def test_to_dict_with_settlement(self) -> None: + ctx = CrossSocietyContext( + sender_lct="lct:alice", + sender_society="lct:society:A", + responding_society="lct:society:B", + atp_settlement_currency="ATP-A", + atp_settlement_amount=50, + ) + d = ctx.to_dict() + settlement = d["cross_society"]["atp_settlement"] + assert settlement["currency"] == "ATP-A" + assert settlement["amount"] == 50 + + def test_roundtrip(self) -> None: + ctx = CrossSocietyContext( + sender_lct="lct:alice", + sender_society="lct:society:A", + responding_society="lct:society:B", + interaction_type=CrossSocietyInteractionType.FEDERATED, + sender_role="web4:role:consumer", + responding_role_expected="web4:role:provider", + applicable_law_oracle="lct:law-oracle:X", + exchange_agreement_hash="sha256:xyz", + atp_settlement_currency="ATP-A", + atp_settlement_amount=100, + atp_settlement_exchange_rate={"rate": 1.2}, + mrh_depth=3, + law_hash="sha256:law", + ) + d = ctx.to_dict() + restored = CrossSocietyContext.from_dict(d) + assert restored.sender_lct == ctx.sender_lct + assert restored.sender_society == ctx.sender_society + assert restored.responding_society == ctx.responding_society + assert restored.interaction_type == ctx.interaction_type + assert restored.sender_role == ctx.sender_role + assert restored.responding_role_expected == ctx.responding_role_expected + assert restored.applicable_law_oracle == ctx.applicable_law_oracle + assert restored.exchange_agreement_hash == ctx.exchange_agreement_hash + assert restored.atp_settlement_currency == ctx.atp_settlement_currency + assert restored.atp_settlement_amount == ctx.atp_settlement_amount + assert restored.atp_settlement_exchange_rate == ctx.atp_settlement_exchange_rate + assert restored.mrh_depth == ctx.mrh_depth + assert restored.law_hash == ctx.law_hash + + def test_frozen(self) -> None: + ctx = CrossSocietyContext( + sender_lct="lct:alice", + sender_society="lct:society:A", + responding_society="lct:society:B", + ) + try: + ctx.sender_lct = "changed" # type: ignore[misc] + assert False, "Should have raised" + except AttributeError: + pass + + +# ── ReputationEnvelope ─────────────────────────────────────────── + + +class TestReputationEnvelope: + def test_minimal_construction(self) -> None: + env = ReputationEnvelope( + action_id="action:123", + outcome_class=OutcomeClass.SUCCESS, + ) + assert env.action_id == "action:123" + assert env.outcome_class is OutcomeClass.SUCCESS + assert env.outcome_quality == 0.5 + assert env.propagation_scope is PropagationScope.RESPONDING_SOCIETY + + def test_full_construction(self) -> None: + env = ReputationEnvelope( + action_id="action:456", + outcome_class=OutcomeClass.PARTIAL, + outcome_quality=0.7, + responding_society="lct:society:B", + responding_society_signature="cose:sig123", + trust_dimension_updates={"talent": 0.01, "training": 0.005}, + propagation_scope=PropagationScope.BOTH, + witness_signatures=["cose:witness1", "cose:witness2"], + timestamp="2026-05-15T12:00:00Z", + ) + assert env.outcome_quality == 0.7 + assert len(env.trust_dimension_updates) == 2 + assert len(env.witness_signatures) == 2 + + def test_to_dict_minimal(self) -> None: + env = ReputationEnvelope( + action_id="action:789", + outcome_class=OutcomeClass.FAILURE, + ) + d = env.to_dict() + assert d["action_id"] == "action:789" + assert d["outcome_class"] == "failure" + assert d["outcome_quality"] == 0.5 + assert d["propagation_scope"] == "responding_society" + assert "responding_society" not in d # empty string omitted + assert "witness_signatures" not in d # empty list omitted + + def test_to_dict_full(self) -> None: + env = ReputationEnvelope( + action_id="action:456", + outcome_class=OutcomeClass.VIOLATION, + outcome_quality=0.1, + responding_society="lct:society:B", + responding_society_signature="cose:sig", + trust_dimension_updates={"temperament": -0.05}, + propagation_scope=PropagationScope.ENCOMPASSING_SOCIETY, + witness_signatures=["cose:w1"], + timestamp="2026-05-15T12:00:00Z", + ) + d = env.to_dict() + assert d["outcome_class"] == "violation" + assert d["responding_society"] == "lct:society:B" + assert d["trust_dimension_updates"]["temperament"] == -0.05 + assert d["propagation_scope"] == "encompassing_society" + assert d["witness_signatures"] == ["cose:w1"] + assert d["timestamp"] == "2026-05-15T12:00:00Z" + + def test_roundtrip(self) -> None: + env = ReputationEnvelope( + action_id="action:rt", + outcome_class=OutcomeClass.PARTIAL, + outcome_quality=0.8, + responding_society="lct:society:X", + responding_society_signature="cose:sigX", + trust_dimension_updates={"talent": 0.02, "training": -0.01}, + propagation_scope=PropagationScope.CALLER_SOCIETY, + witness_signatures=["cose:w1", "cose:w2"], + timestamp="2026-05-15T00:00:00Z", + ) + d = env.to_dict() + restored = ReputationEnvelope.from_dict(d) + assert restored.action_id == env.action_id + assert restored.outcome_class == env.outcome_class + assert restored.outcome_quality == env.outcome_quality + assert restored.responding_society == env.responding_society + assert restored.responding_society_signature == env.responding_society_signature + assert restored.trust_dimension_updates == env.trust_dimension_updates + assert restored.propagation_scope == env.propagation_scope + assert restored.witness_signatures == env.witness_signatures + assert restored.timestamp == env.timestamp + + def test_frozen(self) -> None: + env = ReputationEnvelope( + action_id="action:f", + outcome_class=OutcomeClass.SUCCESS, + ) + try: + env.action_id = "changed" # type: ignore[misc] + assert False, "Should have raised" + except AttributeError: + pass + + +# ── MCPContextResource ─────────────────────────────────────────── + + +class TestMCPContextResource: + def test_minimal_construction(self) -> None: + res = MCPContextResource(name="session_state") + assert res.name == "session_state" + assert res.context_type == "session_state" + assert res.atp_cost == 1 + assert res.ttl == 3600 + + def test_full_construction(self) -> None: + res = MCPContextResource( + name="mrh_snapshot", + context_type="mrh_graph", + description="Current MRH graph snapshot", + trust_requirements=TrustRequirements( + minimum_t3={"talent": 0.5}, + atp_stake=10, + ), + atp_cost=5, + ttl=1800, + snapshot={"nodes": 42, "edges": 100}, + ) + assert res.context_type == "mrh_graph" + assert res.atp_cost == 5 + assert res.snapshot["nodes"] == 42 + + def test_to_dict(self) -> None: + res = MCPContextResource( + name="test_resource", + description="A test resource", + atp_cost=3, + ) + d = res.to_dict() + assert d["resource_type"] == "mcp_context" + assert d["name"] == "test_resource" + assert d["context_type"] == "session_state" + assert d["description"] == "A test resource" + assert d["atp_cost"] == 3 + assert d["ttl"] == 3600 + + def test_roundtrip(self) -> None: + res = MCPContextResource( + name="trust_evolution", + context_type="trust_history", + description="Trust tensor evolution data", + trust_requirements=TrustRequirements( + minimum_t3={"talent": 0.3}, + atp_stake=5, + ), + atp_cost=2, + ttl=7200, + snapshot={"t3_values": [0.5, 0.6, 0.7]}, + ) + d = res.to_dict() + restored = MCPContextResource.from_dict(d) + assert restored.name == res.name + assert restored.context_type == res.context_type + assert restored.description == res.description + assert restored.atp_cost == res.atp_cost + assert restored.ttl == res.ttl + assert restored.snapshot == res.snapshot + + +# ── Cross-Society Error Codes ──────────────────────────────────── + + +class TestCrossSocietyErrors: + def test_error_category_exists(self) -> None: + assert ErrorCategory.CROSS_SOCIETY.value == "CROSS_SOCIETY" + + def test_error_code_count(self) -> None: + cs_codes = codes_for_category(ErrorCategory.CROSS_SOCIETY) + assert len(cs_codes) == 6 + + def test_error_codes_match_spec(self) -> None: + """Verify error codes match mcp-protocol.md §7.6 table.""" + expected = { + ErrorCode.CROSS_SOCIETY_UNRECOGNIZED_LCT: 403, + ErrorCode.CROSS_SOCIETY_EXCHANGE_INVALID: 409, + ErrorCode.CROSS_SOCIETY_LAW_CONFLICT: 409, + ErrorCode.CROSS_SOCIETY_WITNESS_REQUIRED: 412, + ErrorCode.R7_REPUTATION_INVALID: 400, + ErrorCode.PROPAGATION_SCOPE_UNSUPPORTED: 400, + } + for code, status in expected.items(): + meta = get_error_meta(code) + assert meta.status == status, f"{code.name}: expected {status}, got {meta.status}" + assert meta.category == ErrorCategory.CROSS_SOCIETY + + def test_make_error_returns_cross_society_error(self) -> None: + err = make_error(ErrorCode.CROSS_SOCIETY_UNRECOGNIZED_LCT) + assert isinstance(err, CrossSocietyError) + assert isinstance(err, Web4Error) + + def test_from_problem_json_dispatch(self) -> None: + err = make_error( + ErrorCode.CROSS_SOCIETY_LAW_CONFLICT, + detail="Law Oracle X disagrees with Law Oracle Y", + ) + pj = err.to_problem_json() + restored = Web4Error.from_problem_json(pj) + assert isinstance(restored, CrossSocietyError) + assert restored.code == ErrorCode.CROSS_SOCIETY_LAW_CONFLICT + assert "Law Oracle X" in (restored.detail or "") + + def test_all_codes_roundtrip_via_problem_json(self) -> None: + for code in codes_for_category(ErrorCategory.CROSS_SOCIETY): + err = make_error(code, detail=f"Test detail for {code.name}") + pj = err.to_problem_json() + restored = Web4Error.from_problem_json(pj) + assert restored.code == code + assert isinstance(restored, CrossSocietyError) + + +# ── Root Exports ───────────────────────────────────────────────── + + +class TestRootExports: + def test_mcp_types_exported(self) -> None: + import web4 + + for name in [ + "OutcomeClass", + "PropagationScope", + "CrossSocietyInteractionType", + "CrossSocietyContext", + "ReputationEnvelope", + "MCPContextResource", + ]: + assert name in web4.__all__, f"{name} not in web4.__all__" + assert hasattr(web4, name), f"{name} not importable from web4" + + def test_cross_society_error_exported(self) -> None: + import web4 + + assert "CrossSocietyError" in web4.__all__ + assert hasattr(web4, "CrossSocietyError") + + def test_export_count(self) -> None: + import web4 + + assert len(web4.__all__) == 376 diff --git a/web4-standard/implementation/sdk/web4/__init__.py b/web4-standard/implementation/sdk/web4/__init__.py index b5f78e6..df11695 100644 --- a/web4-standard/implementation/sdk/web4/__init__.py +++ b/web4-standard/implementation/sdk/web4/__init__.py @@ -14,7 +14,7 @@ - Reputation computation — rule-based reputation engine with aggregation and decay - Entity taxonomy — behavioral modes, energy patterns, and interaction rules - Capability levels — 6-level LCT capability framework (Stub -> Hardware) -- Error taxonomy — RFC 9457 error types for 6 Web4 protocol categories +- Error taxonomy — RFC 9457 error types for 7 Web4 protocol categories - Metabolic states — society operational modes with energy, trust, and witness effects - Multi-device binding — device constellation management, trust computation, and recovery - Society — core organizational primitive composing federation, treasury, ledger, and trust @@ -27,7 +27,7 @@ - Deserialization — generic JSON-LD dispatcher for all Web4 types - Generation — produce minimal valid JSON-LD documents for any Web4 type -23 modules + MCP server, 369 exports, 2709 tests, 3 behavioral functions, 8 MCP tools, 7 CLI subcommands. +23 modules + MCP server, 376 exports, 2709 tests, 3 behavioral functions, 8 MCP tools, 7 CLI subcommands. v0.27.0: Society roles, Constraint alignment, conformance test runner, validate_minimum_viable. These modules define the canonical data types and algorithms specified in the web4-standard. They work offline (no network services required) and are designed to be @@ -306,6 +306,7 @@ AuthzError, CryptoError, ProtoError, + CrossSocietyError, get_error_meta, codes_for_category, make_error, @@ -486,6 +487,13 @@ MCPErrorContext, web4_context_to_json, web4_context_from_json, + # Cross-society types (mcp-protocol.md §7.3–7.6) + OutcomeClass, + PropagationScope, + CrossSocietyInteractionType, + CrossSocietyContext, + ReputationEnvelope, + MCPContextResource, ) # Aliases for disambiguation with r6 types @@ -741,6 +749,7 @@ "AuthzError", "CryptoError", "ProtoError", + "CrossSocietyError", "get_error_meta", "codes_for_category", "make_error", @@ -895,6 +904,12 @@ "PricingModifiers", "calculate_mcp_cost", "MCPErrorContext", + "OutcomeClass", + "PropagationScope", + "CrossSocietyInteractionType", + "CrossSocietyContext", + "ReputationEnvelope", + "MCPContextResource", "web4_context_to_json", "web4_context_from_json", # validation diff --git a/web4-standard/implementation/sdk/web4/errors.py b/web4-standard/implementation/sdk/web4/errors.py index e5988e7..03307c1 100644 --- a/web4-standard/implementation/sdk/web4/errors.py +++ b/web4-standard/implementation/sdk/web4/errors.py @@ -297,6 +297,49 @@ class ErrorMeta: 400, "Protocol downgrade attack detected", ), + # mcp-protocol.md §7.6 — Cross-Society + ErrorCode.CROSS_SOCIETY_UNRECOGNIZED_LCT: ErrorMeta( + ErrorCode.CROSS_SOCIETY_UNRECOGNIZED_LCT, + ErrorCategory.CROSS_SOCIETY, + "Unrecognized LCT", + 403, + "Caller's LCT not recognized by responding society", + ), + ErrorCode.CROSS_SOCIETY_EXCHANGE_INVALID: ErrorMeta( + ErrorCode.CROSS_SOCIETY_EXCHANGE_INVALID, + ErrorCategory.CROSS_SOCIETY, + "Exchange Rate Invalid", + 409, + "Exchange rate stale or absent for cross-society settlement", + ), + ErrorCode.CROSS_SOCIETY_LAW_CONFLICT: ErrorMeta( + ErrorCode.CROSS_SOCIETY_LAW_CONFLICT, + ErrorCategory.CROSS_SOCIETY, + "Law Oracle Conflict", + 409, + "Applicable Law Oracle disagrees with responding society's Law Oracle", + ), + ErrorCode.CROSS_SOCIETY_WITNESS_REQUIRED: ErrorMeta( + ErrorCode.CROSS_SOCIETY_WITNESS_REQUIRED, + ErrorCategory.CROSS_SOCIETY, + "Witness Required", + 412, + "Witness signature required but absent for cross-society R7", + ), + ErrorCode.R7_REPUTATION_INVALID: ErrorMeta( + ErrorCode.R7_REPUTATION_INVALID, + ErrorCategory.CROSS_SOCIETY, + "Reputation Invalid", + 400, + "R7 reputation envelope signature invalid", + ), + ErrorCode.PROPAGATION_SCOPE_UNSUPPORTED: ErrorMeta( + ErrorCode.PROPAGATION_SCOPE_UNSUPPORTED, + ErrorCategory.CROSS_SOCIETY, + "Propagation Scope Unsupported", + 400, + "Propagation scope unsupported by responding society", + ), } @@ -415,6 +458,12 @@ class ProtoError(Web4Error): pass +class CrossSocietyError(Web4Error): + """Error related to cross-society MCP operations (mcp-protocol.md §7.6).""" + + pass + + # Map categories to their subclass for from_problem_json dispatch _CATEGORY_SUBCLASS: Dict[ErrorCategory, type[Web4Error]] = { ErrorCategory.BINDING: BindingError, @@ -423,6 +472,7 @@ class ProtoError(Web4Error): ErrorCategory.AUTHZ: AuthzError, ErrorCategory.CRYPTO: CryptoError, ErrorCategory.PROTO: ProtoError, + ErrorCategory.CROSS_SOCIETY: CrossSocietyError, } diff --git a/web4-standard/implementation/sdk/web4/mcp.py b/web4-standard/implementation/sdk/web4/mcp.py index 2e57229..9fe9fea 100644 --- a/web4-standard/implementation/sdk/web4/mcp.py +++ b/web4-standard/implementation/sdk/web4/mcp.py @@ -723,9 +723,7 @@ class CrossSocietyContext: sender_lct: str sender_society: str responding_society: str - interaction_type: CrossSocietyInteractionType = ( - CrossSocietyInteractionType.ESTABLISHED - ) + interaction_type: CrossSocietyInteractionType = CrossSocietyInteractionType.ESTABLISHED sender_role: str = "" responding_role_expected: str = "" applicable_law_oracle: str = "" @@ -764,9 +762,7 @@ def to_dict(self) -> Dict[str, Any]: if self.atp_settlement_amount: settlement["amount"] = self.atp_settlement_amount if self.atp_settlement_exchange_rate: - settlement["exchange_rate"] = dict( - self.atp_settlement_exchange_rate - ) + settlement["exchange_rate"] = dict(self.atp_settlement_exchange_rate) cross["atp_settlement"] = settlement d["cross_society"] = cross d["trust_context"] = self.trust_context.to_dict() @@ -800,14 +796,10 @@ def from_dict(cls, d: Dict[str, Any]) -> CrossSocietyContext: atp_settlement_currency=settlement.get("currency", ""), atp_settlement_amount=settlement.get("amount", 0), atp_settlement_exchange_rate=settlement.get("exchange_rate"), - trust_context=TrustContext.from_dict( - d.get("trust_context", {}) - ), + trust_context=TrustContext.from_dict(d.get("trust_context", {})), mrh_depth=d.get("mrh_depth", 1), law_hash=d.get("law_hash", ""), - proof_of_agency=( - ProofOfAgency.from_dict(poa) if poa else None - ), + proof_of_agency=(ProofOfAgency.from_dict(poa) if poa else None), ) @@ -844,13 +836,9 @@ def to_dict(self) -> Dict[str, Any]: if self.responding_society: d["responding_society"] = self.responding_society if self.responding_society_signature: - d["responding_society_signature"] = ( - self.responding_society_signature - ) + d["responding_society_signature"] = self.responding_society_signature if self.trust_dimension_updates: - d["trust_dimension_updates"] = dict( - self.trust_dimension_updates - ) + d["trust_dimension_updates"] = dict(self.trust_dimension_updates) if self.witness_signatures: d["witness_signatures"] = list(self.witness_signatures) if self.timestamp: @@ -865,13 +853,9 @@ def from_dict(cls, d: Dict[str, Any]) -> ReputationEnvelope: outcome_class=OutcomeClass(d["outcome_class"]), outcome_quality=d.get("outcome_quality", 0.5), responding_society=d.get("responding_society", ""), - responding_society_signature=d.get( - "responding_society_signature", "" - ), + responding_society_signature=d.get("responding_society_signature", ""), trust_dimension_updates=d.get("trust_dimension_updates", {}), - propagation_scope=PropagationScope( - d.get("propagation_scope", "responding_society") - ), + propagation_scope=PropagationScope(d.get("propagation_scope", "responding_society")), witness_signatures=d.get("witness_signatures", []), timestamp=d.get("timestamp", ""), ) @@ -892,9 +876,7 @@ class MCPContextResource: name: str context_type: str = "session_state" description: str = "" - trust_requirements: TrustRequirements = field( - default_factory=TrustRequirements - ) + trust_requirements: TrustRequirements = field(default_factory=TrustRequirements) atp_cost: int = 1 ttl: int = 3600 snapshot: Dict[str, Any] = field(default_factory=dict) @@ -922,9 +904,7 @@ def from_dict(cls, d: Dict[str, Any]) -> MCPContextResource: name=d["name"], context_type=d.get("context_type", "session_state"), description=d.get("description", ""), - trust_requirements=TrustRequirements.from_dict( - d.get("trust_requirements", {}) - ), + trust_requirements=TrustRequirements.from_dict(d.get("trust_requirements", {})), atp_cost=d.get("atp_cost", 1), ttl=d.get("ttl", 3600), snapshot=d.get("snapshot", {}),