From e19f7e42518f403b47cf3a1cda1c8ae7f9183bc1 Mon Sep 17 00:00:00 2001 From: Igor Beylin Date: Sun, 30 Aug 2026 15:03:04 -0400 Subject: [PATCH 1/6] Migrate chassis and packet bridge call sites to TransportPacket. Shrinks Cognitive.Engine.Graphs#138 ledger from 18 entries to the two remaining PacketEnvelope unit-test references. inflate/deflate/delegate and PacketBridge now return constellation TransportPacket. Issue-Remediation-Cycle: Quantum-L9/Cognitive.Engine.Graphs#138/cycle-1 Co-authored-by: Cursor --- .l9/baselines/packet-envelope.yml | 194 ---------------------------- chassis/pii.py | 2 +- engine/packet/__init__.py | 7 +- engine/packet/bridge.py | 49 +++++-- engine/packet/chassis_contract.py | 162 ++++++++++++----------- tests/compliance/test_hipaa.py | 2 +- tests/unit/test_chassis_contract.py | 34 +++-- tests/unit/test_packet_bridge.py | 65 ++++------ tests/unit/test_packet_envelope.py | 140 ++++++++++++++------ tools/contract_scanner.py | 6 +- 10 files changed, 276 insertions(+), 385 deletions(-) diff --git a/.l9/baselines/packet-envelope.yml b/.l9/baselines/packet-envelope.yml index 861e537d..13541bad 100644 --- a/.l9/baselines/packet-envelope.yml +++ b/.l9/baselines/packet-envelope.yml @@ -6,188 +6,6 @@ schema_version: 1.0.0 gate: pre-commit/packet-envelope-prohibited entries: -- id: packet-envelope/chassis-pii-py-string-annotation - gate: pre-commit/packet-envelope-prohibited - rule: packet-envelope-prohibited - fingerprint: 63aab1cc36756b7efd32cdbfd8eda3cc2bb8a9f2cd025c480bedcbbb2ba16882 - path: chassis/pii.py - owner: '@cryptoxdog' - issue: Quantum-L9/Cognitive.Engine.Graphs#138 - introduced_before: af986d0 - expires: '2026-10-21' - removal_condition: migrated-to:TransportPacket - root_cause_group: packet-envelope-migration - evidence: chassis/pii.py::string-annotation:For PacketEnvelope.security.pii_fields. -- id: packet-envelope/engine-packet-bridge-py-import-from - gate: pre-commit/packet-envelope-prohibited - rule: packet-envelope-prohibited - fingerprint: 7b4f21c4ddbeea986a8e93dbed41020897e5179bafe50c2eb9358bc7a7c972ec - path: engine/packet/bridge.py - owner: '@cryptoxdog' - issue: Quantum-L9/Cognitive.Engine.Graphs#138 - introduced_before: af986d0 - expires: '2026-10-21' - removal_condition: migrated-to:TransportPacket - root_cause_group: packet-envelope-migration - evidence: engine/packet/bridge.py::import-from:l9_core.models.PacketEnvelope -- id: packet-envelope/engine-packet-bridge-py-name-ref - gate: pre-commit/packet-envelope-prohibited - rule: packet-envelope-prohibited - fingerprint: e35d774a3a4252589559e7b41322d3ac3ce5af5bf2bda71ceed9ed80c42d1a72 - path: engine/packet/bridge.py - owner: '@cryptoxdog' - issue: Quantum-L9/Cognitive.Engine.Graphs#138 - introduced_before: af986d0 - expires: '2026-10-21' - removal_condition: migrated-to:TransportPacket - root_cause_group: packet-envelope-migration - evidence: engine/packet/bridge.py::name-ref:PacketEnvelope -- id: packet-envelope/engine-packet-chassis-contract-py-import-from - gate: pre-commit/packet-envelope-prohibited - rule: packet-envelope-prohibited - fingerprint: 414a2a3cf1dcd99479886e07d23d3d8964cf1996a9f2bf0be80fb2def776bdd7 - path: engine/packet/chassis_contract.py - owner: '@cryptoxdog' - issue: Quantum-L9/Cognitive.Engine.Graphs#138 - introduced_before: af986d0 - expires: '2026-10-21' - removal_condition: migrated-to:TransportPacket - root_cause_group: packet-envelope-migration - evidence: engine/packet/chassis_contract.py::import-from:engine.packet.packet_envelope.PacketEnvelope -- id: packet-envelope/engine-packet-chassis-contract-py-name-ref - gate: pre-commit/packet-envelope-prohibited - rule: packet-envelope-prohibited - fingerprint: 8e9659f3c6354ea6ad139f4040f27e5437c5a9b71e8ff5f455a271e31eac7a43 - path: engine/packet/chassis_contract.py - owner: '@cryptoxdog' - issue: Quantum-L9/Cognitive.Engine.Graphs#138 - introduced_before: af986d0 - expires: '2026-10-21' - removal_condition: migrated-to:TransportPacket - root_cause_group: packet-envelope-migration - evidence: engine/packet/chassis_contract.py::name-ref:PacketEnvelope -- id: packet-envelope/engine-packet-init-py-import-from - gate: pre-commit/packet-envelope-prohibited - rule: packet-envelope-prohibited - fingerprint: 61868c6e8e23cc8a4cef5aa492188293ecbaf1d9faec3bd0445414302ded92eb - path: engine/packet/__init__.py - owner: '@cryptoxdog' - issue: Quantum-L9/Cognitive.Engine.Graphs#138 - introduced_before: af986d0 - expires: '2026-10-21' - removal_condition: migrated-to:TransportPacket - root_cause_group: packet-envelope-migration - evidence: engine/packet/__init__.py::import-from:engine.packet.packet_envelope.PacketEnvelope -- id: packet-envelope/engine-packet-init-py-string-annotation - gate: pre-commit/packet-envelope-prohibited - rule: packet-envelope-prohibited - fingerprint: db1ebe43eae9624dab23bd5f0d15ee97756b2768d2edf5afd1e7e52ba9150ff4 - path: engine/packet/__init__.py - owner: '@cryptoxdog' - issue: Quantum-L9/Cognitive.Engine.Graphs#138 - introduced_before: af986d0 - expires: '2026-10-21' - removal_condition: migrated-to:TransportPacket - root_cause_group: packet-envelope-migration - evidence: engine/packet/__init__.py::string-annotation:PacketEnvelope -- id: packet-envelope/tests-compliance-test-hipaa-py-string-annotation - gate: pre-commit/packet-envelope-prohibited - rule: packet-envelope-prohibited - fingerprint: af1cb57d9fa8ae9571a30700b262a32b0a8b05b4ea2b83e352083e2b8375f610 - path: tests/compliance/test_hipaa.py - owner: '@cryptoxdog' - issue: Quantum-L9/Cognitive.Engine.Graphs#138 - introduced_before: af986d0 - expires: '2026-10-21' - removal_condition: migrated-to:TransportPacket - root_cause_group: packet-envelope-migration - evidence: tests/compliance/test_hipaa.py::string-annotation:get_pii_field_paths returns tuple for PacketEnvelope. -- id: packet-envelope/tests-unit-test-chassis-contract-py-import-from - gate: pre-commit/packet-envelope-prohibited - rule: packet-envelope-prohibited - fingerprint: 203bbd960a496fe4063a34ee4733429c0e20fe950ed45a4f7ce8c634faa5f675 - path: tests/unit/test_chassis_contract.py - owner: '@cryptoxdog' - issue: Quantum-L9/Cognitive.Engine.Graphs#138 - introduced_before: af986d0 - expires: '2026-10-21' - removal_condition: migrated-to:TransportPacket - root_cause_group: packet-envelope-migration - evidence: tests/unit/test_chassis_contract.py::import-from:engine.packet.packet_envelope.PacketEnvelope -- id: packet-envelope/tests-unit-test-chassis-contract-py-name-ref - gate: pre-commit/packet-envelope-prohibited - rule: packet-envelope-prohibited - fingerprint: 7e33b5daae31ef518177c3c534f8a60d891006789a6738ed61bd0dd24ac623ff - path: tests/unit/test_chassis_contract.py - owner: '@cryptoxdog' - issue: Quantum-L9/Cognitive.Engine.Graphs#138 - introduced_before: af986d0 - expires: '2026-10-21' - removal_condition: migrated-to:TransportPacket - root_cause_group: packet-envelope-migration - evidence: tests/unit/test_chassis_contract.py::name-ref:PacketEnvelope -- id: packet-envelope/tests-unit-test-chassis-contract-py-string-annotation - gate: pre-commit/packet-envelope-prohibited - rule: packet-envelope-prohibited - fingerprint: a1e2c583057edf1d051d5059b8585df8107f7b5d32395bc8198f358a4a5bf409 - path: tests/unit/test_chassis_contract.py - owner: '@cryptoxdog' - issue: Quantum-L9/Cognitive.Engine.Graphs#138 - introduced_before: af986d0 - expires: '2026-10-21' - removal_condition: migrated-to:TransportPacket - root_cause_group: packet-envelope-migration - evidence: tests/unit/test_chassis_contract.py::string-annotation:inflate_ingress creates a REQUEST PacketEnvelope. -- id: packet-envelope/tests-unit-test-packet-bridge-py-import-from - gate: pre-commit/packet-envelope-prohibited - rule: packet-envelope-prohibited - fingerprint: 408b19b2fb706e53112dc6982ae6af0989cdba21c0e681242a6f368f920b6d9c - path: tests/unit/test_packet_bridge.py - owner: '@cryptoxdog' - issue: Quantum-L9/Cognitive.Engine.Graphs#138 - introduced_before: af986d0 - expires: '2026-10-21' - removal_condition: migrated-to:TransportPacket - root_cause_group: packet-envelope-migration - evidence: tests/unit/test_packet_bridge.py::import-from:engine.packet.packet_envelope.PacketEnvelope -- id: packet-envelope/tests-unit-test-packet-bridge-py-name-ref - gate: pre-commit/packet-envelope-prohibited - rule: packet-envelope-prohibited - fingerprint: 3895cae07b366e8aa3f09abb09a6fca614557d108546a727e9b311152544e62a - path: tests/unit/test_packet_bridge.py - owner: '@cryptoxdog' - issue: Quantum-L9/Cognitive.Engine.Graphs#138 - introduced_before: af986d0 - expires: '2026-10-21' - removal_condition: migrated-to:TransportPacket - root_cause_group: packet-envelope-migration - evidence: tests/unit/test_packet_bridge.py::name-ref:PacketEnvelope -- id: packet-envelope/tests-unit-test-packet-bridge-py-string-annotation - gate: pre-commit/packet-envelope-prohibited - rule: packet-envelope-prohibited - fingerprint: 2fa54a6107b7c8dc1cecaf781cc5dd9afe5533bc36621d4ac883f70656156c88 - path: tests/unit/test_packet_bridge.py - owner: '@cryptoxdog' - issue: Quantum-L9/Cognitive.Engine.Graphs#138 - introduced_before: af986d0 - expires: '2026-10-21' - removal_condition: migrated-to:TransportPacket - root_cause_group: packet-envelope-migration - evidence: tests/unit/test_packet_bridge.py::string-annotation:PacketEnvelope content hash is deterministic - for same payload. -- id: packet-envelope/tests-unit-test-packet-bridge-py-string-annotation-2 - gate: pre-commit/packet-envelope-prohibited - rule: packet-envelope-prohibited - fingerprint: 3df2d5145062a7cfd8246cddb48bc30d7a26213756c2f856dafedbbda25115cf - path: tests/unit/test_packet_bridge.py - owner: '@cryptoxdog' - issue: Quantum-L9/Cognitive.Engine.Graphs#138 - introduced_before: af986d0 - expires: '2026-10-21' - removal_condition: migrated-to:TransportPacket - root_cause_group: packet-envelope-migration - evidence: tests/unit/test_packet_bridge.py::string-annotation:PacketEnvelope hash changes when payload - differs. - id: packet-envelope/tests-unit-test-packet-envelope-py-import-from gate: pre-commit/packet-envelope-prohibited rule: packet-envelope-prohibited @@ -212,15 +30,3 @@ entries: removal_condition: migrated-to:TransportPacket root_cause_group: packet-envelope-migration evidence: tests/unit/test_packet_envelope.py::name-ref:PacketEnvelope -- id: packet-envelope/tools-contract-scanner-py-string-annotation - gate: pre-commit/packet-envelope-prohibited - rule: packet-envelope-prohibited - fingerprint: 8cd932a0e047bad7a8266c886f5d587f598942f079598628676ba6f0cee5a893 - path: tools/contract_scanner.py - owner: '@cryptoxdog' - issue: Quantum-L9/Cognitive.Engine.Graphs#138 - introduced_before: af986d0 - expires: '2026-10-21' - removal_condition: migrated-to:TransportPacket - root_cause_group: packet-envelope-migration - evidence: tools/contract_scanner.py::string-annotation:from engine.packet.packet_envelope import PacketEnvelope diff --git a/chassis/pii.py b/chassis/pii.py index ef8501a8..0fa2ddbd 100644 --- a/chassis/pii.py +++ b/chassis/pii.py @@ -132,7 +132,7 @@ def detect(self, payload: dict[str, Any], prefix: str = "") -> list[PIIDetection return results def get_pii_paths(self, payload: dict[str, Any]) -> tuple[str, ...]: - """For PacketEnvelope.security.pii_fields.""" + """For TransportPacket.security.pii_fields.""" return tuple(d.field_path for d in self.detect(payload)) def mask(self, payload: dict[str, Any], fields: list[str] | None = None) -> dict[str, Any]: diff --git a/engine/packet/__init__.py b/engine/packet/__init__.py index de1297d9..0d925bfa 100644 --- a/engine/packet/__init__.py +++ b/engine/packet/__init__.py @@ -9,10 +9,11 @@ status: active --- /L9_META --- -engine/packet — PacketEnvelope immutable communication protocol. +engine/packet — TransportPacket chassis bridge. """ +from constellation_node_sdk import TransportPacket + from engine.packet.chassis_contract import deflate_egress, inflate_ingress -from engine.packet.packet_envelope import PacketEnvelope -__all__ = ["PacketEnvelope", "deflate_egress", "inflate_ingress"] +__all__ = ["TransportPacket", "deflate_egress", "inflate_ingress"] diff --git a/engine/packet/bridge.py b/engine/packet/bridge.py index 25a973cb..745627b0 100644 --- a/engine/packet/bridge.py +++ b/engine/packet/bridge.py @@ -14,29 +14,58 @@ from typing import Any -from l9_core.models import PacketEnvelope, make_root_packet +from constellation_node_sdk import TransportPacket, create_transport_packet + +_ALLOWED_PACKET_TYPES = { + "request", + "response", + "event", + "command", + "delegation", + "failure", + "replay_request", + "replay_response", + "compensation", +} class PacketBridge: def inflate_ingress( self, *, tenant_id: str, actor: str, packet_type: str, payload: dict[str, Any] - ) -> PacketEnvelope: - return make_root_packet(packet_type=packet_type, tenant_id=tenant_id, actor=actor, payload=payload) + ) -> TransportPacket: + header_type = packet_type if packet_type in _ALLOWED_PACKET_TYPES else "request" + packet = create_transport_packet( + action=packet_type, + payload=payload, + tenant={ + "actor": actor, + "on_behalf_of": actor, + "originator": actor, + "org_id": tenant_id, + "user_id": None, + }, + source_node="graph", + destination_node="graph", + reply_to="graph", + ) + if header_type != packet.header.packet_type: + return packet.derive(packet_type=header_type) + return packet def attach_entity_semantics( self, *, - packet: PacketEnvelope, + packet: TransportPacket, entity_type: str, canonical_entity_type: str, - ) -> PacketEnvelope: + ) -> TransportPacket: payload = dict(packet.payload) payload["entity_type"] = entity_type payload["canonical_entity_type"] = canonical_entity_type - return packet.derive(packet_type=packet.packet_type, payload=payload) + return packet.derive(payload=payload) - def decision_packet(self, *, packet: PacketEnvelope, decision: dict[str, Any]) -> PacketEnvelope: - return packet.derive(packet_type="routing_decision", payload=decision) + def decision_packet(self, *, packet: TransportPacket, decision: dict[str, Any]) -> TransportPacket: + return packet.derive(packet_type="event", action="routing_decision", payload=decision) - def outcome_packet(self, *, packet: PacketEnvelope, outcome: dict[str, Any]) -> PacketEnvelope: - return packet.derive(packet_type="outcome_event", payload=outcome) + def outcome_packet(self, *, packet: TransportPacket, outcome: dict[str, Any]) -> TransportPacket: + return packet.derive(packet_type="event", action="outcome_event", payload=outcome) diff --git a/engine/packet/chassis_contract.py b/engine/packet/chassis_contract.py index b3362c70..97df34f1 100644 --- a/engine/packet/chassis_contract.py +++ b/engine/packet/chassis_contract.py @@ -9,8 +9,8 @@ status: active --- /L9_META --- """ -# # L9 Chassis ↔ PacketEnvelope v3.0.0 Bridge -# Inflates minimal client JSON → full constellation PacketEnvelope. +# L9 Chassis ↔ TransportPacket bridge +# Inflates minimal client JSON → full constellation TransportPacket. # Deflates engine response → wire-safe outbound envelope. from __future__ import annotations @@ -18,16 +18,18 @@ from datetime import UTC, datetime from typing import Any -from engine.packet.packet_envelope import ( - Action, - HopEntry, - PacketAddress, - PacketEnvelope, - PacketGovernance, - PacketType, - TenantContext, - create_packet, +from constellation_node_sdk import ( + DelegationLink, + TransportGovernance, + TransportPacket, + create_transport_packet, ) +from constellation_node_sdk.transport.hop_trace import make_dispatch_hop, make_response_hop + + +def _action_name(value: Any) -> str: + raw = getattr(value, "value", value) + return str(raw).strip().lower() def inflate_ingress( @@ -42,118 +44,128 @@ def inflate_ingress( on_behalf_of: str | None = None, user_id: str | None = None, org_id: str | None = None, -) -> PacketEnvelope: +) -> TransportPacket: """ Called by the chassis when a client POST /v1/execute arrives. - Minimal input → full PacketEnvelope ready for engine consumption. + Minimal input → full TransportPacket ready for engine consumption. """ - return create_packet( - packet_type=PacketType.REQUEST, - action=Action(action), - source_node=source_node, - actor_tenant=tenant, + actor = tenant.strip() + packet = create_transport_packet( + action=action, payload=payload, - trace_id=trace_id, - on_behalf_of=on_behalf_of, - originator=tenant, - org_id=org_id, - user_id=user_id, + tenant={ + "actor": actor, + "on_behalf_of": (on_behalf_of or actor), + "originator": actor, + "org_id": (org_id or actor), + "user_id": user_id, + }, + source_node=source_node, + destination_node="graph", + reply_to=source_node, classification=classification, - intent=intent, + trace_id=trace_id, ) + if intent: + packet = packet.derive( + governance=TransportGovernance( + intent=intent, + compliance_tags=packet.governance.compliance_tags, + retention_days=packet.governance.retention_days or 90, + redaction_applied=bool(packet.governance.redaction_applied), + audit_required=bool(packet.governance.audit_required), + data_subject_id=packet.governance.data_subject_id, + ) + ) + return packet def deflate_egress( *, - request: PacketEnvelope, + request: TransportPacket, engine_data: dict[str, Any], status: str = "success", processing_ms: float, engine_version: str = "0.0.0", responding_node: str, -) -> PacketEnvelope: +) -> TransportPacket: """ Called by the chassis after engine returns. - Creates a response PacketEnvelope derived from the request. + Creates a response TransportPacket derived from the request. """ now = datetime.now(UTC) - - return request.derive( - packet_type=PacketType.RESPONSE, + destination = request.address.reply_to or request.address.source_node + response = request.derive( + packet_type="response", payload={ "status": status, "data": engine_data, "meta": { - "trace_id": request.observability.trace_id, + "trace_id": request.header.trace_id, "execution_ms": processing_ms, "version": engine_version, "timestamp": now.isoformat(), }, }, - address=PacketAddress( - source_node=responding_node, - destination_node=request.address.reply_to or request.address.source_node, - ), - derivation_type="response", - extra_hop=HopEntry( - node_id=responding_node, - action=request.action.value, - entered_at=request.observability.created_at, - exited_at=now, - status=status, - ), + source_node=responding_node, + destination_node=destination, + reply_to=responding_node, + ) + hop_status = "completed" if status == "success" else "failed" + hop = make_response_hop( + packet=response, + node=responding_node, + action=request.header.action, + status=hop_status, + duration_ms=max(0, int(processing_ms)), + error_message=None if status == "success" else status, ) + return response.with_hop(hop) def delegate_to_node( *, - source_packet: PacketEnvelope, + source_packet: TransportPacket, from_node: str, to_node: str, - delegated_action: Action, + delegated_action: Any, scope: tuple[str, ...], payload_override: dict[str, Any] | None = None, -) -> PacketEnvelope: +) -> TransportPacket: """ Called when one constellation node delegates work to another. Creates a DELEGATION packet with proper tenant context + auth chain. """ - from engine.packet.packet_envelope import DelegationLink - now = datetime.now(UTC) - - return source_packet.derive( - packet_type=PacketType.DELEGATION, - action=delegated_action, - payload=payload_override or source_packet.payload, - address=PacketAddress( - source_node=from_node, - destination_node=to_node, - reply_to=from_node, - ), - tenant=TenantContext( - actor=source_packet.tenant.actor, - on_behalf_of=source_packet.tenant.actor, - originator=source_packet.tenant.originator or source_packet.tenant.actor, - org_id=source_packet.tenant.org_id, - user_id=source_packet.tenant.user_id, - ), - derivation_type="delegation", - extra_hop=HopEntry( - node_id=from_node, - action="delegate", - entered_at=now, - status="delegated", - ), - extra_delegation=DelegationLink( + action = _action_name(delegated_action) + retention = source_packet.governance.retention_days + child = source_packet.derive( + packet_type="delegation", + action=action, + payload=payload_override if payload_override is not None else source_packet.payload, + source_node=from_node, + destination_node=to_node, + reply_to=from_node, + delegation_link=DelegationLink( delegator=from_node, delegatee=to_node, scope=scope, granted_at=now, ), - governance=PacketGovernance( - intent=f"Delegated {delegated_action.value} to {to_node}", + governance=TransportGovernance( + intent=f"Delegated {action} to {to_node}", compliance_tags=source_packet.governance.compliance_tags, + retention_days=90 if retention is None else retention, + redaction_applied=bool(source_packet.governance.redaction_applied), audit_required=True, + data_subject_id=source_packet.governance.data_subject_id, ), ) + hop = make_dispatch_hop( + packet=child, + node=from_node, + action="delegate", + target_node=to_node, + status="delegated", + ) + return child.with_hop(hop) diff --git a/tests/compliance/test_hipaa.py b/tests/compliance/test_hipaa.py index b686e4de..d88fd7c4 100644 --- a/tests/compliance/test_hipaa.py +++ b/tests/compliance/test_hipaa.py @@ -63,7 +63,7 @@ def test_detect_nested_pii(self) -> None: assert "patient.contact.phone" in paths def test_get_pii_field_paths(self) -> None: - """get_pii_field_paths returns tuple for PacketEnvelope.""" + """get_pii_field_paths returns tuple for TransportPacket.""" handler = PIIHandler() payload = {"email": "a@b.com", "ssn": "111-22-3333", "id": 1} diff --git a/tests/unit/test_chassis_contract.py b/tests/unit/test_chassis_contract.py index 61ec35b9..b83a3fe0 100644 --- a/tests/unit/test_chassis_contract.py +++ b/tests/unit/test_chassis_contract.py @@ -16,17 +16,13 @@ from __future__ import annotations import pytest +from constellation_node_sdk import TransportPacket from engine.packet.chassis_contract import ( deflate_egress, delegate_to_node, inflate_ingress, ) -from engine.packet.packet_envelope import ( - Action, - PacketEnvelope, - PacketType, -) # ============================================================================ # TEST CLASSES @@ -38,16 +34,16 @@ class TestInflateIngress: """Test inflate_ingress function.""" def test_creates_request_packet(self) -> None: - """inflate_ingress creates a REQUEST PacketEnvelope.""" + """inflate_ingress creates a REQUEST TransportPacket.""" packet = inflate_ingress( action="match", payload={"query": {"polymer": "HDPE"}}, tenant="test-tenant", trace_id="tr_abc123", ) - assert isinstance(packet, PacketEnvelope) - assert packet.packet_type == PacketType.REQUEST - assert packet.action == Action("match") + assert isinstance(packet, TransportPacket) + assert packet.header.packet_type == "request" + assert packet.header.action == "match" assert packet.tenant.actor == "test-tenant" assert packet.payload["query"]["polymer"] == "HDPE" @@ -60,7 +56,7 @@ def test_with_all_optional_params(self) -> None: trace_id="tr_1", source_node="api-gateway", intent="batch_sync", - classification="external", + classification="confidential", on_behalf_of="admin_user", user_id="u_123", org_id="org_456", @@ -79,14 +75,14 @@ def test_default_source_node_is_chassis(self) -> None: assert packet.address.source_node == "chassis" def test_trace_id_preserved(self) -> None: - """inflate_ingress sets trace_id in observability.""" + """inflate_ingress sets trace_id on the transport header.""" packet = inflate_ingress( action="match", payload={}, tenant="t1", trace_id="my_trace", ) - assert packet.observability.trace_id == "my_trace" + assert packet.header.trace_id == "my_trace" @pytest.mark.unit @@ -108,7 +104,7 @@ def test_creates_response_from_request(self) -> None: processing_ms=42.5, responding_node="graph-engine-1", ) - assert response.packet_type == PacketType.RESPONSE + assert response.header.packet_type == "response" assert response.payload["status"] == "success" assert response.payload["data"]["candidates"][0]["score"] == pytest.approx(0.95) assert response.payload["meta"]["execution_ms"] == pytest.approx(42.5) @@ -162,11 +158,11 @@ def test_creates_delegation_packet(self) -> None: source_packet=source, from_node="graph-engine", to_node="enrich-engine", - delegated_action=Action("enrich"), + delegated_action="enrich", scope=("entity_enrichment",), ) - assert delegation.packet_type == PacketType.DELEGATION - assert delegation.action == Action("enrich") + assert delegation.header.packet_type == "delegation" + assert delegation.header.action == "enrich" assert delegation.address.source_node == "graph-engine" assert delegation.address.destination_node == "enrich-engine" @@ -182,7 +178,7 @@ def test_copies_tenant_context(self) -> None: source_packet=source, from_node="a", to_node="b", - delegated_action=Action("sync"), + delegated_action="sync", scope=("data_sync",), ) assert delegation.tenant.actor == "original_tenant" @@ -199,7 +195,7 @@ def test_sets_audit_required(self) -> None: source_packet=source, from_node="a", to_node="b", - delegated_action=Action("admin"), + delegated_action="admin", scope=("admin_ops",), ) assert delegation.governance.audit_required is True @@ -216,7 +212,7 @@ def test_payload_override(self) -> None: source_packet=source, from_node="a", to_node="b", - delegated_action=Action("enrich"), + delegated_action="enrich", scope=("enrich",), payload_override={"overridden": True}, ) diff --git a/tests/unit/test_packet_bridge.py b/tests/unit/test_packet_bridge.py index 633c929c..b3513c83 100644 --- a/tests/unit/test_packet_bridge.py +++ b/tests/unit/test_packet_bridge.py @@ -1,4 +1,4 @@ -"""Unit tests — PacketEnvelope bridge: hash determinism, payload sensitivity. +"""Unit tests — TransportPacket bridge: hash determinism, payload sensitivity. Note: These tests require chassis integration modules that may not be implemented. Tests skip gracefully if required modules are not available. @@ -9,49 +9,35 @@ import pytest -def test_packet_envelope_content_hash_is_deterministic(): - """PacketEnvelope content hash is deterministic for same payload.""" +def test_transport_packet_payload_hash_is_deterministic(): + """TransportPacket payload hash is deterministic for same payload.""" try: - from engine.chassis.tenant_context import TenantContext - - from engine.packet.packet_envelope import PacketEnvelope, PacketType + from constellation_node_sdk import create_transport_packet except ImportError: - pytest.skip("engine.chassis or engine.packet.packet_envelope not implemented") - tenant = TenantContext(tenant_id="test", actor="unit-test") - p1 = PacketEnvelope( - packet_type=PacketType.REQUEST, - tenant=tenant, + pytest.skip("constellation_node_sdk not installed") + p1 = create_transport_packet( + action="match", payload={"action": "match", "x": 1}, + tenant="test", ) - p2 = PacketEnvelope( - packet_type=PacketType.REQUEST, - tenant=tenant, + p2 = create_transport_packet( + action="match", payload={"action": "match", "x": 1}, + tenant="test", ) - assert p1.content_hash == p2.content_hash - assert len(p1.content_hash) == 64 # SHA-256 hex + assert p1.security.payload_hash == p2.security.payload_hash + assert len(p1.security.payload_hash) == 64 # SHA-256 hex -def test_packet_envelope_hash_changes_with_payload(): - """PacketEnvelope hash changes when payload differs.""" +def test_transport_packet_hash_changes_with_payload(): + """TransportPacket payload hash changes when payload differs.""" try: - from engine.chassis.tenant_context import TenantContext - - from engine.packet.packet_envelope import PacketEnvelope, PacketType + from constellation_node_sdk import create_transport_packet except ImportError: - pytest.skip("engine.chassis or engine.packet.packet_envelope not implemented") - tenant = TenantContext(tenant_id="test", actor="unit-test") - p1 = PacketEnvelope( - packet_type=PacketType.REQUEST, - tenant=tenant, - payload={"action": "match"}, - ) - p2 = PacketEnvelope( - packet_type=PacketType.REQUEST, - tenant=tenant, - payload={"action": "sync"}, - ) - assert p1.content_hash != p2.content_hash + pytest.skip("constellation_node_sdk not installed") + p1 = create_transport_packet(action="match", payload={"action": "match"}, tenant="test") + p2 = create_transport_packet(action="sync", payload={"action": "sync"}, tenant="test") + assert p1.security.payload_hash != p2.security.payload_hash def test_packet_bridge_inflate_ingress(): @@ -67,8 +53,9 @@ def test_packet_bridge_inflate_ingress(): packet_type="graph_sync", payload={"entity_type": "Facility", "batch": []}, ) - assert packet.packet_type == "graph_sync" - assert packet.content_hash + assert packet.header.action == "graph_sync" + assert packet.header.packet_type == "request" + assert packet.security.payload_hash assert packet.lineage.root_id @@ -85,7 +72,7 @@ def test_packet_bridge_derive_preserves_lineage(): packet_type="graph_sync", payload={"entity_type": "Facility"}, ) - derived = root.derive("outcome_event", {"result": "ok"}) + derived = root.derive(packet_type="event", action="outcome_event", payload={"result": "ok"}) assert derived.lineage.root_id == root.lineage.root_id - assert derived.lineage.parent_id == root.packet_id - assert derived.lineage.hop_count == 1 + assert derived.lineage.parent_id == root.header.packet_id + assert derived.lineage.generation == 1 diff --git a/tests/unit/test_packet_envelope.py b/tests/unit/test_packet_envelope.py index 2c7842d2..f1c7681c 100644 --- a/tests/unit/test_packet_envelope.py +++ b/tests/unit/test_packet_envelope.py @@ -247,12 +247,18 @@ def test_derive_can_override_tags(self, base_packet): class TestDelegation: - def test_delegate_creates_delegation_link(self, base_packet): + def test_delegate_creates_delegation_link(self): + source = inflate_ingress( + action="match", + payload={"polymer": "HDPE"}, + tenant="acme_recycling", + trace_id="tr-delegate", + ) delegated = delegate_to_node( - source_packet=base_packet, + source_packet=source, from_node="orchestrator", to_node="enrichment-api", - delegated_action=Action.ENRICH, + delegated_action="enrich", scope=("enrich",), ) assert len(delegated.delegation_chain) == 1 @@ -261,54 +267,78 @@ def test_delegate_creates_delegation_link(self, base_packet): assert link.delegatee == "enrichment-api" assert link.scope == ("enrich",) - def test_delegate_sets_on_behalf_of(self, base_packet): + def test_delegate_sets_on_behalf_of(self): + source = inflate_ingress( + action="match", + payload={}, + tenant="acme_recycling", + trace_id="tr-behalf", + ) delegated = delegate_to_node( - source_packet=base_packet, + source_packet=source, from_node="orchestrator", to_node="enrichment-api", - delegated_action=Action.ENRICH, + delegated_action="enrich", scope=("enrich",), ) assert delegated.tenant.on_behalf_of == "acme_recycling" - def test_delegate_adds_hop(self, base_packet): + def test_delegate_adds_hop(self): + source = inflate_ingress( + action="match", + payload={}, + tenant="acme_recycling", + trace_id="tr-hop-del", + ) delegated = delegate_to_node( - source_packet=base_packet, + source_packet=source, from_node="orchestrator", to_node="enrichment-api", - delegated_action=Action.ENRICH, + delegated_action="enrich", scope=("enrich",), ) assert len(delegated.hop_trace) == 1 - assert delegated.hop_trace[0].node_id == "orchestrator" + assert delegated.hop_trace[0].node == "orchestrator" assert delegated.hop_trace[0].status == "delegated" - def test_stacked_delegation(self, base_packet): + def test_stacked_delegation(self): + source = inflate_ingress( + action="match", + payload={}, + tenant="acme_recycling", + trace_id="tr-stack", + ) d1 = delegate_to_node( - source_packet=base_packet, + source_packet=source, from_node="agent", to_node="plasticos", - delegated_action=Action.MATCH, + delegated_action="match", scope=("match",), ) d2 = delegate_to_node( source_packet=d1, from_node="plasticos", to_node="enrichment", - delegated_action=Action.ENRICH, + delegated_action="enrich", scope=("enrich",), ) assert len(d2.delegation_chain) == 2 - assert len(d2.hop_trace) == 2 + assert len(d2.hop_trace) >= 1 assert d2.lineage.generation == 2 - assert d2.lineage.root_id == base_packet.packet_id + assert d2.lineage.root_id == source.lineage.root_id - def test_delegation_sets_audit_required(self, base_packet): + def test_delegation_sets_audit_required(self): + source = inflate_ingress( + action="match", + payload={}, + tenant="acme", + trace_id="tr-audit", + ) delegated = delegate_to_node( - source_packet=base_packet, + source_packet=source, from_node="a", to_node="b", - delegated_action=Action.ENRICH, + delegated_action="enrich", scope=("enrich",), ) assert delegated.governance.audit_required is True @@ -337,16 +367,22 @@ def test_roundtrip_preserves_lineage(self, base_packet): assert restored.lineage.generation == 1 assert str(base_packet.packet_id) in [str(pid) for pid in restored.lineage.parent_ids] - def test_roundtrip_preserves_delegation_chain(self, base_packet): + def test_roundtrip_preserves_delegation_chain(self): + source = inflate_ingress( + action="match", + payload={}, + tenant="acme", + trace_id="tr-wire-del", + ) delegated = delegate_to_node( - source_packet=base_packet, + source_packet=source, from_node="a", to_node="b", - delegated_action=Action.ENRICH, + delegated_action="enrich", scope=("enrich",), ) - wire = delegated.to_wire() - restored = PacketEnvelope.from_wire(wire) + assert len(delegated.delegation_chain) == 1 + restored = type(delegated).model_validate_json(delegated.model_dump_json()) assert len(restored.delegation_chain) == 1 def test_roundtrip_preserves_pii_fields(self, base_packet): @@ -366,10 +402,10 @@ def test_inflate(self): tenant="acme", trace_id="tr-1", ) - assert pkt.packet_type == PacketType.REQUEST - assert pkt.action == Action.MATCH + assert pkt.header.packet_type == "request" + assert pkt.header.action == "match" assert pkt.tenant.actor == "acme" - assert pkt.verify_integrity() + assert pkt.security.payload_hash def test_inflate_with_delegation(self): pkt = inflate_ingress( @@ -381,33 +417,51 @@ def test_inflate_with_delegation(self): ) assert pkt.tenant.on_behalf_of == "parent_tenant" - def test_deflate(self, base_packet): + def test_deflate(self): + request = inflate_ingress( + action="match", + payload={"polymer": "HDPE"}, + tenant="acme", + trace_id="tr-deflate", + ) resp = deflate_egress( - request=base_packet, + request=request, engine_data={"matches": [1, 2, 3]}, processing_ms=42.5, engine_version="1.0.0", responding_node="match-engine", ) - assert resp.packet_type == PacketType.RESPONSE + assert resp.header.packet_type == "response" assert resp.payload["status"] == "success" - assert base_packet.packet_id in resp.lineage.parent_ids - assert resp.verify_integrity() + assert resp.lineage.parent_id == request.header.packet_id + assert resp.security.payload_hash - def test_deflate_adds_hop(self, base_packet): + def test_deflate_adds_hop(self): + request = inflate_ingress( + action="match", + payload={}, + tenant="acme", + trace_id="tr-hop", + ) resp = deflate_egress( - request=base_packet, + request=request, engine_data={}, processing_ms=10.0, engine_version="1.0.0", responding_node="match-engine", ) assert len(resp.hop_trace) == 1 - assert resp.hop_trace[0].node_id == "match-engine" + assert resp.hop_trace[0].node == "match-engine" - def test_deflate_includes_execution_meta(self, base_packet): + def test_deflate_includes_execution_meta(self): + request = inflate_ingress( + action="match", + payload={}, + tenant="acme", + trace_id="tr-meta", + ) resp = deflate_egress( - request=base_packet, + request=request, engine_data={}, processing_ms=55.3, engine_version="2.1.0", @@ -433,12 +487,18 @@ def test_originator_defaults_to_actor(self): ) assert pkt.tenant.originator == "t1" - def test_multi_tenant_delegation_preserves_originator(self, base_packet): + def test_multi_tenant_delegation_preserves_originator(self): + source = inflate_ingress( + action="match", + payload={}, + tenant="acme_recycling", + trace_id="tr-originator", + ) d = delegate_to_node( - source_packet=base_packet, + source_packet=source, from_node="agent", to_node="other-engine", - delegated_action=Action.ENRICH, + delegated_action="enrich", scope=("enrich",), ) assert d.tenant.originator == "acme_recycling" diff --git a/tools/contract_scanner.py b/tools/contract_scanner.py index dd4bef21..89b7f014 100644 --- a/tools/contract_scanner.py +++ b/tools/contract_scanner.py @@ -233,9 +233,9 @@ def _rule( "SHARED-001", SHARED_MODELS_MD, "HIGH", - r"class\s+PacketEnvelope\s*\(", - "Redefining PacketEnvelope - import the shared model", - "from engine.packet.packet_envelope import PacketEnvelope", + r"class\s+TransportPacket\s*\(", + "Redefining TransportPacket - import the shared model", + "from constellation_node_sdk import TransportPacket", include_dirs=[ENGINE_DIR], exclude_dirs=["engine/packet/packet_envelope.py"], # canonical envelope in this repo ), From 0f39b3c11f873ec7bb72658d1c1f74f4cce9dd4c Mon Sep 17 00:00:00 2001 From: Igor Beylin Date: Sun, 30 Aug 2026 15:03:46 -0400 Subject: [PATCH 2/6] Refresh issue session-ref for PacketEnvelope cycle 1. Issue-Remediation-Cycle: Quantum-L9/Cognitive.Engine.Graphs#138/cycle-1 Co-authored-by: Cursor --- TODO.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/TODO.md b/TODO.md index f6f509b9..6c2b9965 100644 --- a/TODO.md +++ b/TODO.md @@ -1,9 +1,9 @@ ## Issue unblock (session reference) -**Cluster:** CEG#32 (mypy chassis) + CEG#33 (YAML) — closed 2026-08-11 as already clean on main -**Owning fix:** none (evidence close; `mypy chassis/` clean; listed YAML parse OK) -**Next:** optional CI hygiene — drop `--exclude chassis` from mypy workflow steps (CI_PIPELINE; not done) -**Pickup:** Graphiti PICKUP written 2026-08-11 +**Cluster:** CEG#138 (PacketEnvelope → TransportPacket) cycle 1 + CEG#139 (quarantine) queued +**Owning fix:** https://github.com/Quantum-L9/Cognitive.Engine.Graphs/pull/248 +**Next:** migrate `tests/unit/test_packet_envelope.py` then delete last 2 ledger entries; do not close #138 until then +**Pickup:** Graphiti PICKUP written 2026-08-30