File size: 8,405 Bytes
fc3e70a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

"""Phase 2: Semantic IR β€” typed intermediate representation, the canonical source of truth."""

from __future__ import annotations

import hashlib
import uuid
from dataclasses import dataclass, field
from typing import Any, Optional

from .types import (
    ArtifactType, IntentClass, Provenance, SemanticNodeType,
    TemporalViolation, VerificationState, FSMState,
)


# ── Geometry ──────────────────────────────────────────────────────────────────

@dataclass(frozen=True)
class Geometry:
    """Explicit dimensional description of an operation's operands."""
    row: Optional[int] = None
    col: Optional[int] = None
    contraction: Optional[int] = None
    shape: tuple[int, ...] = field(default_factory=tuple)
    index_labels: tuple[str, ...] = field(default_factory=tuple)

    def compatible_with(self, other: Geometry) -> bool:
        """Check whether self and other can be contracted (matrix multiply)."""
        if self.col is None or other.row is None:
            return True  # undetermined β€” not a violation yet
        return self.col == other.row

    def output_geometry(self, other: Geometry) -> Geometry:
        if self.row is None or other.col is None:
            return Geometry()
        return Geometry(row=self.row, col=other.col, contraction=self.col)


# ── Temporal state ────────────────────────────────────────────────────────────

@dataclass
class TemporalState:
    tau: int  # monotonic integer tick
    label: str = ""
    locked: bool = False

    def advance(self, reason: str = "") -> TemporalState:
        if self.locked:
            raise TemporalViolation(FSMState.TEMPORAL_LOCK, "Cannot advance a locked temporal state")
        return TemporalState(tau=self.tau + 1, label=reason)

    def lock(self) -> TemporalState:
        return TemporalState(tau=self.tau, label=self.label, locked=True)


@dataclass(frozen=True)
class TemporalTransition:
    from_tau: int
    to_tau: int
    reason: str
    stage: str

    def is_valid(self) -> bool:
        return self.to_tau == self.from_tau + 1 or self.to_tau == self.from_tau


@dataclass
class TemporalLock:
    transitions: list[TemporalTransition] = field(default_factory=list)

    def record(self, t: TemporalTransition) -> None:
        if not t.is_valid():
            raise TemporalViolation(
                FSMState.TEMPORAL_LOCK,
                f"Invalid temporal jump: Ο„{t.from_tau} β†’ Ο„{t.to_tau} (expected +1 or 0)",
            )
        self.transitions.append(t)

    def audit(self) -> list[TemporalTransition]:
        return list(self.transitions)


# ── Core IR nodes ─────────────────────────────────────────────────────────────

@dataclass
class Operand:
    name: str
    type_tag: str
    value: Any = None
    geometry: Optional[Geometry] = None

    @property
    def node_id(self) -> str:
        return hashlib.sha256(f"operand:{self.name}:{self.type_tag}".encode()).hexdigest()[:16]


@dataclass
class Constraint:
    constraint_id: str
    description: str
    predicate: str
    operands: list[str] = field(default_factory=list)

    @staticmethod
    def make(description: str, predicate: str, operands: list[str] | None = None) -> Constraint:
        cid = hashlib.sha256(f"{predicate}:{description}".encode()).hexdigest()[:16]
        return Constraint(
            constraint_id=cid,
            description=description,
            predicate=predicate,
            operands=operands or [],
        )


@dataclass
class SemanticOperation:
    name: str
    arity: int
    description: str = ""
    associative: bool = False
    commutative: bool = False

    @property
    def op_id(self) -> str:
        return hashlib.sha256(f"op:{self.name}:{self.arity}".encode()).hexdigest()[:16]


@dataclass
class SemanticNode:
    id: str
    type: SemanticNodeType
    operation: Optional[SemanticOperation]
    operands: list[Operand]
    constraints: list[Constraint]
    geometry: Optional[Geometry]
    temporal_state: TemporalState
    provenance: Provenance
    children: list[SemanticNode] = field(default_factory=list)
    metadata: dict[str, Any] = field(default_factory=dict)

    @staticmethod
    def make(
        node_type: SemanticNodeType,
        operation: Optional[SemanticOperation],
        operands: list[Operand],
        constraints: list[Constraint],
        geometry: Optional[Geometry],
        temporal_state: TemporalState,
        provenance: Provenance,
    ) -> SemanticNode:
        content = f"{node_type}:{operation}:{[o.name for o in operands]}"
        node_id = hashlib.sha256(content.encode()).hexdigest()[:24]
        return SemanticNode(
            id=node_id,
            type=node_type,
            operation=operation,
            operands=operands,
            constraints=constraints,
            geometry=geometry,
            temporal_state=temporal_state,
            provenance=provenance,
        )

    def hash(self) -> str:
        content = f"{self.id}:{self.type}:{self.operation}:{len(self.operands)}"
        return hashlib.sha256(content.encode()).hexdigest()


# ── Semantic IR root ──────────────────────────────────────────────────────────

@dataclass
class SemanticIR:
    ir_id: str
    intent: IntentClass
    root: SemanticNode
    nodes: list[SemanticNode]
    temporal_lock: TemporalLock
    provenance: Provenance
    verification_state: VerificationState = VerificationState.UNVERIFIED
    output_mode: str = "natural_language"
    metadata: dict[str, Any] = field(default_factory=dict)

    @staticmethod
    def create(
        intent: IntentClass,
        root: SemanticNode,
        nodes: list[SemanticNode],
        temporal_lock: TemporalLock,
        provenance: Provenance,
    ) -> SemanticIR:
        ir_id = str(uuid.uuid4())
        return SemanticIR(
            ir_id=ir_id,
            intent=intent,
            root=root,
            nodes=nodes,
            temporal_lock=temporal_lock,
            provenance=provenance,
        )

    def hash(self) -> str:
        node_hashes = ":".join(n.hash() for n in self.nodes)
        return hashlib.sha256(f"{self.ir_id}:{self.intent}:{node_hashes}".encode()).hexdigest()

    def add_node(self, node: SemanticNode) -> None:
        self.nodes.append(node)

    def find_node(self, node_id: str) -> Optional[SemanticNode]:
        return next((n for n in self.nodes if n.id == node_id), None)


# ── Artifact IR ───────────────────────────────────────────────────────────────

@dataclass
class Artifact:
    id: str
    type: ArtifactType
    semantic_root: str  # SemanticIR.ir_id
    template: str
    content: str
    provenance: Provenance
    temporal_state: TemporalState
    verification_state: VerificationState = VerificationState.UNVERIFIED
    metadata: dict[str, Any] = field(default_factory=dict)

    @staticmethod
    def create(
        artifact_type: ArtifactType,
        semantic_root: str,
        template: str,
        content: str,
        provenance: Provenance,
        temporal_state: TemporalState,
    ) -> Artifact:
        artifact_id = hashlib.sha256(
            f"{artifact_type}:{semantic_root}:{content[:64]}".encode()
        ).hexdigest()[:24]
        return Artifact(
            id=artifact_id,
            type=artifact_type,
            semantic_root=semantic_root,
            template=template,
            content=content,
            provenance=provenance,
            temporal_state=temporal_state,
        )

    def hash(self) -> str:
        return hashlib.sha256(
            f"{self.id}:{self.type}:{self.content}".encode()
        ).hexdigest()