cortex-runtime 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cortex/__init__.py +51 -0
- cortex/__main__.py +13 -0
- cortex/client.py +263 -0
- cortex/compat.py +20 -0
- cortex/exceptions.py +57 -0
- cortex/plugin.py +50 -0
- cortex/py.typed +1 -0
- cortex/schema/__init__.py +29 -0
- cortex/schema/events.py +127 -0
- cortex/tools/__init__.py +3 -0
- cortex/tools/cli/__init__.py +3 -0
- cortex/tools/cli/main.py +139 -0
- cortex/tools/cli/runner.py +94 -0
- cortex/tools/cli/scaffolder.py +109 -0
- cortex/tools/gen_test_bin.py +35 -0
- cortex/tools/kernel/__init__.py +3 -0
- cortex/tools/kernel/actors/__init__.py +3 -0
- cortex/tools/kernel/actors/executor.py +44 -0
- cortex/tools/kernel/actors/planner.py +38 -0
- cortex/tools/kernel/context.py +22 -0
- cortex/tools/kernel/drivers/__init__.py +3 -0
- cortex/tools/kernel/drivers/mock_robot.py +84 -0
- cortex/tools/kernel/drivers/rtl_verilator.py +49 -0
- cortex/tools/kernel/graph/__init__.py +3 -0
- cortex/tools/kernel/graph/analyzer.py +52 -0
- cortex/tools/kernel/graph/execution_graph.py +44 -0
- cortex/tools/kernel/mailbox.py +35 -0
- cortex/tools/kernel/plugin/__init__.py +3 -0
- cortex/tools/kernel/plugin/loader.py +87 -0
- cortex/tools/kernel/plugin/manifest.py +53 -0
- cortex/tools/kernel/registry.py +36 -0
- cortex/tools/kernel/schema/__init__.py +3 -0
- cortex/tools/kernel/schema/contract.py +16 -0
- cortex/tools/kernel/schema/event.py +54 -0
- cortex/tools/kernel/schema/message.py +105 -0
- cortex/tools/kernel/schema/workflow.py +38 -0
- cortex/tools/kernel/services/__init__.py +3 -0
- cortex/tools/kernel/services/event_store.py +25 -0
- cortex/tools/kernel/services/execution_intelligence.py +49 -0
- cortex/tools/kernel/services/graph_builder.py +81 -0
- cortex/tools/kernel/services/replay.py +50 -0
- cortex/tools/kernel/services/verification.py +85 -0
- cortex/tools/kernel/transport.py +50 -0
- cortex/tools/run_phase2_verification.sh +20 -0
- cortex/tools/verification/__init__.py +5 -0
- cortex/tools/verification/adapters/__init__.py +3 -0
- cortex/tools/verification/adapters/base.py +14 -0
- cortex/tools/verification/adapters/coq.py +73 -0
- cortex/tools/verification/adapters/rtl.py +77 -0
- cortex/tools/verification/adapters/rust.py +72 -0
- cortex/tools/verification/archive.py +58 -0
- cortex/tools/verification/bus.py +28 -0
- cortex/tools/verification/contract.py +70 -0
- cortex/tools/verification/engine.py +121 -0
- cortex/tools/verification/generator/__init__.py +3 -0
- cortex/tools/verification/generator/composer.py +36 -0
- cortex/tools/verification/generator/program.py +46 -0
- cortex/tools/verification/generator/state.py +54 -0
- cortex/tools/verification/invariants/__init__.py +3 -0
- cortex/tools/verification/invariants/capability.py +62 -0
- cortex/tools/verification/metrics/__init__.py +3 -0
- cortex/tools/verification/metrics/base.py +18 -0
- cortex/tools/verification/metrics/opcode.py +25 -0
- cortex/tools/verification/metrics/state_space.py +26 -0
- cortex/tools/verification/metrics/trap.py +26 -0
- cortex/tools/verification/mutation.py +48 -0
- cortex/tools/verification/oracle.py +164 -0
- cortex/tools/verification/schema/__init__.py +44 -0
- cortex/tools/verification/schema/event.py +44 -0
- cortex/tools/verification/shrink.py +26 -0
- cortex/tools/verify.py +64 -0
- cortex_runtime-0.2.0.dist-info/METADATA +220 -0
- cortex_runtime-0.2.0.dist-info/RECORD +76 -0
- cortex_runtime-0.2.0.dist-info/WHEEL +4 -0
- cortex_runtime-0.2.0.dist-info/entry_points.txt +2 -0
- cortex_runtime-0.2.0.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Execution Graph Builder Service
|
|
3
|
+
|
|
4
|
+
Consumes: IntentEvent, PlanGeneratedEvent, CommandIssuedEvent,
|
|
5
|
+
DriverTelemetryEvent, VerificationResultEvent (via BaseEvent wildcard)
|
|
6
|
+
Produces: (none — pure projection / read model)
|
|
7
|
+
|
|
8
|
+
Constructs a real-time Directed Acyclic Graph (DAG) from the stream
|
|
9
|
+
of kernel messages. Each node is linked to its causal parent via the
|
|
10
|
+
message identity fields (intent_id, plan_id, command_id, causation_id).
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from cortex.tools.kernel.graph.execution_graph import ExecutionGraph
|
|
16
|
+
from cortex.tools.kernel.schema.message import (
|
|
17
|
+
BaseEvent,
|
|
18
|
+
CommandIssuedEvent,
|
|
19
|
+
DriverTelemetryEvent,
|
|
20
|
+
IntentEvent,
|
|
21
|
+
PlanGeneratedEvent,
|
|
22
|
+
VerificationResultEvent,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ExecutionGraphBuilderService:
|
|
27
|
+
graphs: dict[str, ExecutionGraph]
|
|
28
|
+
|
|
29
|
+
def __init__(self):
|
|
30
|
+
self.graphs = {}
|
|
31
|
+
|
|
32
|
+
def record_message(self, msg: Any) -> None:
|
|
33
|
+
if isinstance(msg, IntentEvent):
|
|
34
|
+
graph = ExecutionGraph(root_id=msg.intent_id)
|
|
35
|
+
graph.add_node(
|
|
36
|
+
node_id=msg.intent_id,
|
|
37
|
+
node_type="Intent",
|
|
38
|
+
payload={"goal": msg.goal},
|
|
39
|
+
)
|
|
40
|
+
self.graphs[msg.intent_id] = graph
|
|
41
|
+
|
|
42
|
+
elif isinstance(msg, PlanGeneratedEvent):
|
|
43
|
+
graph = self.graphs.get(msg.intent_id)
|
|
44
|
+
if graph:
|
|
45
|
+
graph.add_node(
|
|
46
|
+
node_id=msg.plan_id,
|
|
47
|
+
node_type="Plan",
|
|
48
|
+
payload={"step_count": len(msg.steps)},
|
|
49
|
+
parent_id=msg.intent_id,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
elif isinstance(msg, CommandIssuedEvent):
|
|
53
|
+
for graph in self.graphs.values():
|
|
54
|
+
if msg.plan_id in graph.nodes:
|
|
55
|
+
graph.add_node(
|
|
56
|
+
node_id=msg.command_id,
|
|
57
|
+
node_type="Command",
|
|
58
|
+
payload={"action": msg.action, "params": msg.parameters},
|
|
59
|
+
parent_id=msg.plan_id,
|
|
60
|
+
)
|
|
61
|
+
break
|
|
62
|
+
|
|
63
|
+
elif isinstance(msg, BaseEvent):
|
|
64
|
+
for graph in self.graphs.values():
|
|
65
|
+
if msg.causation_id and msg.causation_id in graph.nodes:
|
|
66
|
+
node_type = "Event"
|
|
67
|
+
payload: dict[str, object] = {}
|
|
68
|
+
if isinstance(msg, DriverTelemetryEvent):
|
|
69
|
+
node_type = "Telemetry"
|
|
70
|
+
payload = {"status": msg.status, "data": msg.payload}
|
|
71
|
+
elif isinstance(msg, VerificationResultEvent):
|
|
72
|
+
node_type = "Verification"
|
|
73
|
+
payload = {"passed": msg.passed, "rule": msg.rule_id}
|
|
74
|
+
|
|
75
|
+
graph.add_node(
|
|
76
|
+
node_id=msg.event_id,
|
|
77
|
+
node_type=node_type,
|
|
78
|
+
payload=payload,
|
|
79
|
+
parent_id=msg.causation_id,
|
|
80
|
+
)
|
|
81
|
+
break
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Deterministic Replay Subsystem for Kernel Event Streams
|
|
3
|
+
|
|
4
|
+
Replays recorded event journals and validates that causal lineage
|
|
5
|
+
(event_id, causation_id ordering) is perfectly preserved.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from cortex.tools.kernel.schema.message import BaseEvent
|
|
9
|
+
from cortex.tools.kernel.transport import EventPublisher
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DeterministicReplayEngine:
|
|
13
|
+
"""Executes deterministic replay of recorded event journals."""
|
|
14
|
+
publisher: EventPublisher
|
|
15
|
+
|
|
16
|
+
def __init__(self, publisher: EventPublisher):
|
|
17
|
+
self.publisher = publisher
|
|
18
|
+
|
|
19
|
+
def replay_journal(self, journal: list[BaseEvent]) -> int:
|
|
20
|
+
"""Replays an ordered event journal onto the target transport."""
|
|
21
|
+
replayed_count = 0
|
|
22
|
+
for event in journal:
|
|
23
|
+
self.publisher.publish(event)
|
|
24
|
+
replayed_count += 1
|
|
25
|
+
return replayed_count
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def verify_replayed_lineage(
|
|
29
|
+
original: list[BaseEvent], replayed: list[BaseEvent]
|
|
30
|
+
) -> dict[str, object]:
|
|
31
|
+
"""Validates 1:1 causal ID and event sequence immutability."""
|
|
32
|
+
if len(original) != len(replayed):
|
|
33
|
+
return {
|
|
34
|
+
"match": False,
|
|
35
|
+
"reason": f"Length mismatch: original={len(original)}, replayed={len(replayed)}",
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
for idx, (orig, repl) in enumerate(zip(original, replayed)):
|
|
39
|
+
if orig.event_id != repl.event_id:
|
|
40
|
+
return {
|
|
41
|
+
"match": False,
|
|
42
|
+
"reason": f"Event ID mismatch at index {idx}: {orig.event_id} != {repl.event_id}",
|
|
43
|
+
}
|
|
44
|
+
if orig.causation_id != repl.causation_id:
|
|
45
|
+
return {
|
|
46
|
+
"match": False,
|
|
47
|
+
"reason": f"Causation ID mismatch at index {idx}: {orig.causation_id} != {repl.causation_id}",
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {"match": True, "reason": "100% Deterministic Lineage Preservation Confirmed"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Verification Service Kernel Contract
|
|
3
|
+
|
|
4
|
+
Consumes: RawRTLTraceEvent (verification domain), DriverTelemetryEvent (kernel domain)
|
|
5
|
+
Produces: CommitVerifiedEvent (verification domain), VerificationResultEvent (kernel domain)
|
|
6
|
+
|
|
7
|
+
This service bridges two event hierarchies:
|
|
8
|
+
1. The verification substrate (event.py: RawRTLTraceEvent → CommitVerifiedEvent)
|
|
9
|
+
2. The kernel runtime (message.py: DriverTelemetryEvent → VerificationResultEvent)
|
|
10
|
+
|
|
11
|
+
This is an intentional design decision — the verification service is the
|
|
12
|
+
only component that legitimately spans both domains.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from collections.abc import Callable
|
|
16
|
+
|
|
17
|
+
from cortex.tools.kernel.context import RuntimeContext
|
|
18
|
+
from cortex.tools.kernel.schema.contract import ServiceContract
|
|
19
|
+
from cortex.tools.kernel.schema.event import CommitVerifiedEvent, RawRTLTraceEvent
|
|
20
|
+
from cortex.tools.kernel.schema.message import (
|
|
21
|
+
DriverTelemetryEvent,
|
|
22
|
+
VerificationResultEvent,
|
|
23
|
+
)
|
|
24
|
+
from cortex.tools.kernel.transport import AnyEvent
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class VerificationKernelService:
|
|
28
|
+
context: RuntimeContext
|
|
29
|
+
publish_cb: Callable[[AnyEvent], object]
|
|
30
|
+
verified_count: int
|
|
31
|
+
|
|
32
|
+
contract = ServiceContract(
|
|
33
|
+
service_name="VerificationKernelService",
|
|
34
|
+
consumes=[RawRTLTraceEvent, DriverTelemetryEvent],
|
|
35
|
+
produces=[CommitVerifiedEvent, VerificationResultEvent],
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def __init__(self, context: RuntimeContext, publish_cb: Callable[[AnyEvent], object] | None = None):
|
|
39
|
+
self.context = context
|
|
40
|
+
self.publish_cb = publish_cb or context.publish
|
|
41
|
+
self.verified_count = 0
|
|
42
|
+
|
|
43
|
+
# -- Verification Domain (event.py hierarchy) --------------------------
|
|
44
|
+
|
|
45
|
+
def handle_raw_rtl_trace(self, event: RawRTLTraceEvent) -> None:
|
|
46
|
+
"""Evaluates RTL trace frames against CommitContractV1 invariants."""
|
|
47
|
+
self.verified_count += 1
|
|
48
|
+
is_valid = True
|
|
49
|
+
failing_field = None
|
|
50
|
+
|
|
51
|
+
if event.eff_trap and event.trap_cause == 0:
|
|
52
|
+
is_valid = False
|
|
53
|
+
failing_field = "trap_cause"
|
|
54
|
+
|
|
55
|
+
verified_event = CommitVerifiedEvent(
|
|
56
|
+
parent_event_id=event.event_id,
|
|
57
|
+
root_event_id=event.root_event_id or event.event_id,
|
|
58
|
+
causation_id=event.event_id,
|
|
59
|
+
correlation_id=event.correlation_id,
|
|
60
|
+
session_id=event.session_id,
|
|
61
|
+
step=event.sequence_number,
|
|
62
|
+
verified=is_valid,
|
|
63
|
+
failing_field=failing_field,
|
|
64
|
+
)
|
|
65
|
+
self.publish_cb(verified_event)
|
|
66
|
+
|
|
67
|
+
# -- Kernel Runtime Domain (message.py hierarchy) ----------------------
|
|
68
|
+
|
|
69
|
+
def handle_telemetry(self, event: DriverTelemetryEvent) -> VerificationResultEvent:
|
|
70
|
+
"""Evaluates driver telemetry against runtime safety invariants."""
|
|
71
|
+
self.verified_count += 1
|
|
72
|
+
raw_pos: object = event.payload.get("position", 0.0)
|
|
73
|
+
pos = float(str(raw_pos)) if isinstance(raw_pos, (int, float, str)) else 0.0
|
|
74
|
+
passed = abs(pos) <= 100.0
|
|
75
|
+
|
|
76
|
+
result = VerificationResultEvent(
|
|
77
|
+
causation_id=event.event_id,
|
|
78
|
+
correlation_id=event.correlation_id,
|
|
79
|
+
root_id=event.root_id,
|
|
80
|
+
passed=passed,
|
|
81
|
+
rule_id="BOUNDS_CHECK_V1",
|
|
82
|
+
metrics={"position": pos},
|
|
83
|
+
)
|
|
84
|
+
self.publish_cb(result)
|
|
85
|
+
return result
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Transport Layer Abstractions & InMemoryTransport Implementation
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
|
|
8
|
+
from cortex.compat import override
|
|
9
|
+
from cortex.tools.kernel.schema.event import Event
|
|
10
|
+
from cortex.tools.kernel.schema.message import BaseEvent
|
|
11
|
+
|
|
12
|
+
AnyEvent = Event | BaseEvent
|
|
13
|
+
EventHandler = Callable[[AnyEvent], None]
|
|
14
|
+
|
|
15
|
+
class EventPublisher(ABC):
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def publish(self, event: AnyEvent) -> None:
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
class EventSubscriber(ABC):
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def subscribe(self, event_type: type[AnyEvent], handler: EventHandler) -> None:
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
class InMemoryTransport(EventPublisher, EventSubscriber):
|
|
26
|
+
_handlers: dict[type[AnyEvent], list[EventHandler]]
|
|
27
|
+
_history: list[AnyEvent]
|
|
28
|
+
|
|
29
|
+
def __init__(self):
|
|
30
|
+
self._handlers = {}
|
|
31
|
+
self._history = []
|
|
32
|
+
|
|
33
|
+
@override
|
|
34
|
+
def subscribe(self, event_type: type[AnyEvent], handler: EventHandler) -> None:
|
|
35
|
+
if event_type not in self._handlers:
|
|
36
|
+
self._handlers[event_type] = []
|
|
37
|
+
self._handlers[event_type].append(handler)
|
|
38
|
+
|
|
39
|
+
@override
|
|
40
|
+
def publish(self, event: AnyEvent) -> None:
|
|
41
|
+
self._history.append(event)
|
|
42
|
+
# Notify subscribers of exact type or wildcard Event base class
|
|
43
|
+
for event_cls, handlers in self._handlers.items():
|
|
44
|
+
if issubclass(type(event), event_cls):
|
|
45
|
+
for handler in handlers:
|
|
46
|
+
handler(event)
|
|
47
|
+
|
|
48
|
+
def get_history(self) -> list[AnyEvent]:
|
|
49
|
+
return list(self._history)
|
|
50
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Cortex Spatiotemporal Authority Core — Phase 2 Audit Verification Runner
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
7
|
+
|
|
8
|
+
cd "${ROOT_DIR}"
|
|
9
|
+
|
|
10
|
+
echo "[+] Building SystemVerilog RTL and C++ Testbench with Verilator..."
|
|
11
|
+
make verilate
|
|
12
|
+
|
|
13
|
+
echo "[+] Running Verilator RTL Simulation against canonical payload..."
|
|
14
|
+
make run-rtl
|
|
15
|
+
|
|
16
|
+
echo "[+] Running 3-Way Differential Trace Equivalence Verifier..."
|
|
17
|
+
python3 cortex-emulator/tests/diff_harness.py \
|
|
18
|
+
Research/artifacts/phase2/coq_trace.json \
|
|
19
|
+
Research/artifacts/phase2/emulator_trace.json \
|
|
20
|
+
rtl_trace.json
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Abstract Base Adapter for Target Output Normalization
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from cortex.tools.verification.schema import CanonicalState
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BaseAdapter(ABC):
|
|
12
|
+
@abstractmethod
|
|
13
|
+
def parse_trace(self, trace_input: Any) -> list[CanonicalState]:
|
|
14
|
+
"""Converts raw engine trace into list of CanonicalState objects."""
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Coq Operational Semantics Trace Adapter
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from cortex.tools.verification.adapters.base import BaseAdapter
|
|
9
|
+
from cortex.tools.verification.schema import (
|
|
10
|
+
CanonicalState,
|
|
11
|
+
CanonicalSTCR,
|
|
12
|
+
CanonicalTrap,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CoqAdapter(BaseAdapter):
|
|
17
|
+
def parse_trace(self, trace_input: Any) -> list[CanonicalState]:
|
|
18
|
+
if isinstance(trace_input, str):
|
|
19
|
+
with open(trace_input) as f:
|
|
20
|
+
data = json.load(f)
|
|
21
|
+
else:
|
|
22
|
+
data = trace_input
|
|
23
|
+
|
|
24
|
+
canonical_steps = []
|
|
25
|
+
for frame in data:
|
|
26
|
+
step_id = frame.get("step_id", frame.get("step", 0))
|
|
27
|
+
pc = frame.get("pc", 0)
|
|
28
|
+
reg_hec = frame.get("reg_hec", 0)
|
|
29
|
+
raw_inst = frame.get("instruction", {}).get("raw_hex", "0x00000000")
|
|
30
|
+
|
|
31
|
+
outcome = frame.get("outcome", {})
|
|
32
|
+
status = outcome.get("status", "OK")
|
|
33
|
+
is_trap = (status == "EFF_TRAP")
|
|
34
|
+
trap_cause_name = outcome.get("trap_cause", "None")
|
|
35
|
+
dest_val = outcome.get("dest_reg_val", 0)
|
|
36
|
+
|
|
37
|
+
# Map trap cause name to integer code
|
|
38
|
+
trap_codes = {
|
|
39
|
+
"None": 0,
|
|
40
|
+
"InsufficientSpatialRights": 1,
|
|
41
|
+
"EpochMismatch": 2,
|
|
42
|
+
"InvalidCapability": 3,
|
|
43
|
+
"IllegalInstruction": 15
|
|
44
|
+
}
|
|
45
|
+
cause_code = trap_codes.get(trap_cause_name, 1 if is_trap else 0)
|
|
46
|
+
|
|
47
|
+
stcr_list = []
|
|
48
|
+
for stcr in frame.get("stcr_file", []):
|
|
49
|
+
stcr_list.append(CanonicalSTCR(
|
|
50
|
+
index=stcr.get("id", 0),
|
|
51
|
+
valid=stcr.get("valid", False),
|
|
52
|
+
permissions=stcr.get("spatial_mask", 0),
|
|
53
|
+
base_address=stcr.get("base_address", 0),
|
|
54
|
+
epoch=stcr.get("max_epoch", 0)
|
|
55
|
+
))
|
|
56
|
+
|
|
57
|
+
canonical_steps.append(CanonicalState(
|
|
58
|
+
step=step_id,
|
|
59
|
+
pc=pc,
|
|
60
|
+
instruction=raw_inst,
|
|
61
|
+
privilege_mode="Machine",
|
|
62
|
+
reg_hec=reg_hec,
|
|
63
|
+
registers={"dest_val": f"0x{dest_val:016x}"},
|
|
64
|
+
stcr=stcr_list,
|
|
65
|
+
trap=CanonicalTrap(
|
|
66
|
+
triggered=is_trap,
|
|
67
|
+
cause_code=cause_code,
|
|
68
|
+
cause_name=trap_cause_name,
|
|
69
|
+
trap_val=dest_val
|
|
70
|
+
)
|
|
71
|
+
))
|
|
72
|
+
|
|
73
|
+
return canonical_steps
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Verilator SystemVerilog RTL Trace Adapter
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from cortex.tools.verification.adapters.base import BaseAdapter
|
|
9
|
+
from cortex.tools.verification.schema import (
|
|
10
|
+
CanonicalState,
|
|
11
|
+
CanonicalSTCR,
|
|
12
|
+
CanonicalTrap,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class RTLAdapter(BaseAdapter):
|
|
17
|
+
def parse_trace(self, trace_input: Any) -> list[CanonicalState]:
|
|
18
|
+
if isinstance(trace_input, str):
|
|
19
|
+
with open(trace_input) as f:
|
|
20
|
+
data = json.load(f)
|
|
21
|
+
else:
|
|
22
|
+
data = trace_input
|
|
23
|
+
|
|
24
|
+
frames = data.get("trace", data) if isinstance(data, dict) else data
|
|
25
|
+
|
|
26
|
+
canonical_steps = []
|
|
27
|
+
for frame in frames:
|
|
28
|
+
step_id = frame.get("step", 0)
|
|
29
|
+
pc = frame.get("pc", 0)
|
|
30
|
+
reg_hec = frame.get("reg_hec", 0)
|
|
31
|
+
raw_inst = frame.get("raw_instruction", "0x00000000")
|
|
32
|
+
is_trap = frame.get("eff_trap", False)
|
|
33
|
+
cause_code = frame.get("trap_cause", 0)
|
|
34
|
+
|
|
35
|
+
cause_names = {
|
|
36
|
+
0: "None",
|
|
37
|
+
1: "InsufficientSpatialRights",
|
|
38
|
+
2: "EpochMismatch",
|
|
39
|
+
3: "InvalidCapability",
|
|
40
|
+
15: "IllegalInstruction"
|
|
41
|
+
}
|
|
42
|
+
cause_name = cause_names.get(cause_code, "UnknownTrap" if is_trap else "None")
|
|
43
|
+
|
|
44
|
+
stcr_list = []
|
|
45
|
+
raw_stcr_array = frame.get("stcr_registers", [])
|
|
46
|
+
for reg_id, raw_hex in enumerate(raw_stcr_array):
|
|
47
|
+
val = int(raw_hex, 16) if isinstance(raw_hex, str) else raw_hex
|
|
48
|
+
valid = bool((val >> 63) & 1)
|
|
49
|
+
perms = (val >> 48) & 0x7FFF
|
|
50
|
+
base = (val >> 16) & 0xFFFFFFFF
|
|
51
|
+
epoch = val & 0xFFFF
|
|
52
|
+
|
|
53
|
+
stcr_list.append(CanonicalSTCR(
|
|
54
|
+
index=reg_id,
|
|
55
|
+
valid=valid,
|
|
56
|
+
permissions=perms,
|
|
57
|
+
base_address=base,
|
|
58
|
+
epoch=epoch
|
|
59
|
+
))
|
|
60
|
+
|
|
61
|
+
canonical_steps.append(CanonicalState(
|
|
62
|
+
step=step_id,
|
|
63
|
+
pc=pc,
|
|
64
|
+
instruction=raw_inst,
|
|
65
|
+
privilege_mode="Machine",
|
|
66
|
+
reg_hec=reg_hec,
|
|
67
|
+
registers={},
|
|
68
|
+
stcr=stcr_list,
|
|
69
|
+
trap=CanonicalTrap(
|
|
70
|
+
triggered=is_trap,
|
|
71
|
+
cause_code=cause_code,
|
|
72
|
+
cause_name=cause_name,
|
|
73
|
+
trap_val=0
|
|
74
|
+
)
|
|
75
|
+
))
|
|
76
|
+
|
|
77
|
+
return canonical_steps
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Rust Reference Emulator Trace Adapter
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from cortex.tools.verification.adapters.base import BaseAdapter
|
|
9
|
+
from cortex.tools.verification.schema import (
|
|
10
|
+
CanonicalState,
|
|
11
|
+
CanonicalSTCR,
|
|
12
|
+
CanonicalTrap,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class RustAdapter(BaseAdapter):
|
|
17
|
+
def parse_trace(self, trace_input: Any) -> list[CanonicalState]:
|
|
18
|
+
if isinstance(trace_input, str):
|
|
19
|
+
with open(trace_input) as f:
|
|
20
|
+
data = json.load(f)
|
|
21
|
+
else:
|
|
22
|
+
data = trace_input
|
|
23
|
+
|
|
24
|
+
canonical_steps = []
|
|
25
|
+
for frame in data:
|
|
26
|
+
step_id = frame.get("step_id", frame.get("step", 0))
|
|
27
|
+
pc = frame.get("pc", 0)
|
|
28
|
+
reg_hec = frame.get("reg_hec", 0)
|
|
29
|
+
raw_inst = frame.get("instruction", {}).get("raw_hex", "0x00000000")
|
|
30
|
+
|
|
31
|
+
outcome = frame.get("outcome", {})
|
|
32
|
+
status = outcome.get("status", "OK")
|
|
33
|
+
is_trap = (status == "EFF_TRAP")
|
|
34
|
+
trap_cause_name = outcome.get("trap_cause", "None")
|
|
35
|
+
dest_val = outcome.get("dest_reg_val", 0)
|
|
36
|
+
|
|
37
|
+
trap_codes = {
|
|
38
|
+
"None": 0,
|
|
39
|
+
"InsufficientSpatialRights": 1,
|
|
40
|
+
"EpochMismatch": 2,
|
|
41
|
+
"InvalidCapability": 3,
|
|
42
|
+
"IllegalInstruction": 15
|
|
43
|
+
}
|
|
44
|
+
cause_code = trap_codes.get(trap_cause_name, 1 if is_trap else 0)
|
|
45
|
+
|
|
46
|
+
stcr_list = []
|
|
47
|
+
for stcr in frame.get("stcr_file", []):
|
|
48
|
+
stcr_list.append(CanonicalSTCR(
|
|
49
|
+
index=stcr.get("id", 0),
|
|
50
|
+
valid=stcr.get("valid", False),
|
|
51
|
+
permissions=stcr.get("spatial_mask", 0),
|
|
52
|
+
base_address=stcr.get("base_address", 0),
|
|
53
|
+
epoch=stcr.get("max_epoch", 0)
|
|
54
|
+
))
|
|
55
|
+
|
|
56
|
+
canonical_steps.append(CanonicalState(
|
|
57
|
+
step=step_id,
|
|
58
|
+
pc=pc,
|
|
59
|
+
instruction=raw_inst,
|
|
60
|
+
privilege_mode="Machine",
|
|
61
|
+
reg_hec=reg_hec,
|
|
62
|
+
registers={"dest_val": f"0x{dest_val:016x}"},
|
|
63
|
+
stcr=stcr_list,
|
|
64
|
+
trap=CanonicalTrap(
|
|
65
|
+
triggered=is_trap,
|
|
66
|
+
cause_code=cause_code,
|
|
67
|
+
cause_name=trap_cause_name,
|
|
68
|
+
trap_val=dest_val
|
|
69
|
+
)
|
|
70
|
+
))
|
|
71
|
+
|
|
72
|
+
return canonical_steps
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Index-backed Counterexample Database Archiver
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import hashlib
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CounterexampleArchive:
|
|
12
|
+
def __init__(self, archive_dir: str = "artifacts/counterexamples/"):
|
|
13
|
+
self.archive_dir = archive_dir
|
|
14
|
+
self.index_path = os.path.join(self.archive_dir, "index.json")
|
|
15
|
+
os.makedirs(self.archive_dir, exist_ok=True)
|
|
16
|
+
if not os.path.exists(self.index_path):
|
|
17
|
+
with open(self.index_path, "w") as f:
|
|
18
|
+
json.dump({"counterexamples": []}, f, indent=2)
|
|
19
|
+
|
|
20
|
+
def archive_failure(
|
|
21
|
+
self,
|
|
22
|
+
scenario: dict[str, Any],
|
|
23
|
+
diagnostic: dict[str, Any],
|
|
24
|
+
seed: str,
|
|
25
|
+
commit_id: str = "a484b94"
|
|
26
|
+
) -> str:
|
|
27
|
+
payload_str = json.dumps(scenario, sort_keys=True).encode("utf-8")
|
|
28
|
+
entry_hash = hashlib.sha256(payload_str).hexdigest()[:12]
|
|
29
|
+
|
|
30
|
+
case_dir = os.path.join(self.archive_dir, entry_hash)
|
|
31
|
+
os.makedirs(case_dir, exist_ok=True)
|
|
32
|
+
|
|
33
|
+
case_file = os.path.join(case_dir, "scenario.json")
|
|
34
|
+
diag_file = os.path.join(case_dir, "diagnostic.json")
|
|
35
|
+
|
|
36
|
+
with open(case_file, "w") as f:
|
|
37
|
+
json.dump(scenario, f, indent=2)
|
|
38
|
+
|
|
39
|
+
with open(diag_file, "w") as f:
|
|
40
|
+
json.dump(diagnostic, f, indent=2)
|
|
41
|
+
|
|
42
|
+
# Update index.json
|
|
43
|
+
with open(self.index_path, "r") as f:
|
|
44
|
+
index_data = json.load(f)
|
|
45
|
+
|
|
46
|
+
index_data["counterexamples"].append({
|
|
47
|
+
"hash": entry_hash,
|
|
48
|
+
"seed": seed,
|
|
49
|
+
"commit_id": commit_id,
|
|
50
|
+
"error_type": diagnostic.get("error_type", "Unknown"),
|
|
51
|
+
"mismatched_field": diagnostic.get("mismatched_field", "Unknown"),
|
|
52
|
+
"failing_step": diagnostic.get("failing_step", 0)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
with open(self.index_path, "w") as f:
|
|
56
|
+
json.dump(index_data, f, indent=2)
|
|
57
|
+
|
|
58
|
+
return entry_hash
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Typed Append-Only Event Bus for Broadcasting Immutable CommitEventV1 Instances
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
|
|
7
|
+
from cortex.tools.verification.schema.event import CommitEventV1
|
|
8
|
+
|
|
9
|
+
SubscriberCallback = Callable[[CommitEventV1], None]
|
|
10
|
+
|
|
11
|
+
class EventBus:
|
|
12
|
+
def __init__(self):
|
|
13
|
+
self._subscribers: list[SubscriberCallback] = []
|
|
14
|
+
self._history: list[CommitEventV1] = []
|
|
15
|
+
|
|
16
|
+
def subscribe(self, callback: SubscriberCallback) -> None:
|
|
17
|
+
self._subscribers.append(callback)
|
|
18
|
+
|
|
19
|
+
def publish(self, event: CommitEventV1) -> None:
|
|
20
|
+
self._history.append(event)
|
|
21
|
+
for subscriber in self._subscribers:
|
|
22
|
+
subscriber(event)
|
|
23
|
+
|
|
24
|
+
def get_history(self) -> list[CommitEventV1]:
|
|
25
|
+
return list(self._history)
|
|
26
|
+
|
|
27
|
+
def clear(self) -> None:
|
|
28
|
+
self._history.clear()
|