the-grid-cc 1.1.0

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.
@@ -0,0 +1,228 @@
1
+ """
2
+ Cluster - Collection of related Blocks.
3
+
4
+ "Clusters organize the computational landscape of The Grid."
5
+ """
6
+
7
+ from dataclasses import dataclass, field
8
+ from datetime import datetime
9
+ from typing import Optional
10
+ from enum import Enum
11
+ import uuid
12
+
13
+ from .block import Block, BlockStatus
14
+ from .energy import EnergyPool
15
+
16
+
17
+ class ClusterStatus(Enum):
18
+ """Status of a Cluster."""
19
+ PENDING = "pending"
20
+ RUNNING = "running"
21
+ COMPLETED = "completed"
22
+ FAILED = "failed"
23
+ DEREZZED = "derezzed"
24
+
25
+
26
+ class Cluster:
27
+ """
28
+ Cluster - Collection of related Blocks (feature/domain group).
29
+
30
+ Clusters represent a major feature or domain area.
31
+ They contain Blocks that work together toward a shared goal.
32
+ """
33
+
34
+ def __init__(
35
+ self,
36
+ name: str,
37
+ purpose: str,
38
+ description: str = "",
39
+ ):
40
+ self.id = str(uuid.uuid4())[:8]
41
+ self.name = name
42
+ self.purpose = purpose
43
+ self.description = description
44
+
45
+ self.status = ClusterStatus.PENDING
46
+ self.created_at = datetime.now()
47
+ self.started_at: Optional[datetime] = None
48
+ self.completed_at: Optional[datetime] = None
49
+
50
+ # Blocks in this Cluster
51
+ self.blocks: dict[str, Block] = {}
52
+ self.block_order: list[str] = [] # Execution order
53
+
54
+ # Energy
55
+ self.energy_pool: Optional[EnergyPool] = None
56
+
57
+ # I/O Tower checkpoints
58
+ self.io_tower_checkpoints: list[str] = []
59
+
60
+ def add_block(
61
+ self,
62
+ name: str,
63
+ purpose: str,
64
+ blocked_by: list[str] = None,
65
+ ) -> Block:
66
+ """Add a new Block to this Cluster."""
67
+ block = Block(
68
+ name=name,
69
+ purpose=purpose,
70
+ cluster_id=self.id,
71
+ blocked_by=blocked_by,
72
+ )
73
+ self.blocks[block.id] = block
74
+ self.block_order.append(block.id)
75
+ return block
76
+
77
+ def get_block(self, block_id: str) -> Optional[Block]:
78
+ """Get a Block by ID."""
79
+ return self.blocks.get(block_id)
80
+
81
+ def get_block_by_name(self, name: str) -> Optional[Block]:
82
+ """Get a Block by name."""
83
+ for block in self.blocks.values():
84
+ if block.name == name:
85
+ return block
86
+ return None
87
+
88
+ def start(self) -> None:
89
+ """Start Cluster execution."""
90
+ self.status = ClusterStatus.RUNNING
91
+ self.started_at = datetime.now()
92
+
93
+ def get_runnable_blocks(self) -> list[Block]:
94
+ """Get Blocks that can start (not blocked by other Blocks)."""
95
+ completed = {
96
+ b.name for b in self.blocks.values()
97
+ if b.status == BlockStatus.COMPLETED
98
+ }
99
+ return [
100
+ b for b in self.blocks.values()
101
+ if b.status == BlockStatus.PENDING and b.can_start(completed)
102
+ ]
103
+
104
+ def get_running_blocks(self) -> list[Block]:
105
+ """Get currently running Blocks."""
106
+ return [
107
+ b for b in self.blocks.values()
108
+ if b.status == BlockStatus.RUNNING
109
+ ]
110
+
111
+ def get_completed_blocks(self) -> list[Block]:
112
+ """Get completed Blocks."""
113
+ return [
114
+ b for b in self.blocks.values()
115
+ if b.status == BlockStatus.COMPLETED
116
+ ]
117
+
118
+ def all_blocks_completed(self) -> bool:
119
+ """Check if all Blocks are completed."""
120
+ return all(
121
+ b.status in (BlockStatus.COMPLETED, BlockStatus.DEREZZED)
122
+ for b in self.blocks.values()
123
+ )
124
+
125
+ def any_block_failed(self) -> bool:
126
+ """Check if any Block failed."""
127
+ return any(
128
+ b.status == BlockStatus.FAILED
129
+ for b in self.blocks.values()
130
+ )
131
+
132
+ def complete(self) -> None:
133
+ """Mark Cluster as completed."""
134
+ self.status = ClusterStatus.COMPLETED
135
+ self.completed_at = datetime.now()
136
+ # Return unused energy
137
+ if self.energy_pool:
138
+ self.energy_pool.return_unused()
139
+
140
+ def fail(self) -> None:
141
+ """Mark Cluster as failed."""
142
+ self.status = ClusterStatus.FAILED
143
+ self.completed_at = datetime.now()
144
+
145
+ def derez(self) -> None:
146
+ """Mark Cluster as derezzed."""
147
+ self.status = ClusterStatus.DEREZZED
148
+ for block in self.blocks.values():
149
+ block.derez()
150
+
151
+ def progress(self) -> float:
152
+ """Get overall Cluster progress (0-100)."""
153
+ if not self.blocks:
154
+ return 0.0
155
+ total_progress = sum(b.progress() for b in self.blocks.values())
156
+ return total_progress / len(self.blocks)
157
+
158
+ def total_threads(self) -> int:
159
+ """Get total number of Threads across all Blocks."""
160
+ return sum(len(b.threads) for b in self.blocks.values())
161
+
162
+ def completed_threads(self) -> int:
163
+ """Get number of completed Threads."""
164
+ return sum(len(b.get_completed_threads()) for b in self.blocks.values())
165
+
166
+ def energy_consumed(self) -> int:
167
+ """Get total energy consumed by this Cluster."""
168
+ return sum(b.energy_consumed() for b in self.blocks.values())
169
+
170
+ def duration(self) -> Optional[float]:
171
+ """Get execution duration in seconds."""
172
+ if not self.started_at:
173
+ return None
174
+ end = self.completed_at or datetime.now()
175
+ return (end - self.started_at).total_seconds()
176
+
177
+ def add_io_checkpoint(self, reason: str) -> None:
178
+ """Add an I/O Tower checkpoint."""
179
+ self.io_tower_checkpoints.append(reason)
180
+
181
+ def display_full(self) -> str:
182
+ """Get full display for status views."""
183
+ energy_display = ""
184
+ if self.energy_pool:
185
+ energy_display = f"Energy: {self.energy_pool.remaining}"
186
+
187
+ lines = [
188
+ "╔" + "═" * 77 + "╗",
189
+ f"║ CLUSTER: {self.name:<50} {energy_display:>15} ║",
190
+ "╠" + "═" * 77 + "╣",
191
+ "║" + " " * 77 + "║",
192
+ ]
193
+
194
+ for block_id in self.block_order:
195
+ block = self.blocks[block_id]
196
+ for line in block.display_box().split("\n"):
197
+ lines.append(f"║ {line:<75}║")
198
+ lines.append("║" + " " * 77 + "║")
199
+
200
+ # I/O Tower checkpoints
201
+ for checkpoint in self.io_tower_checkpoints:
202
+ lines.append(f"║ ⛯ I/O TOWER: {checkpoint:<61}║")
203
+
204
+ lines.append("║" + " " * 77 + "║")
205
+ lines.append("╚" + "═" * 77 + "╝")
206
+
207
+ return "\n".join(lines)
208
+
209
+ def to_dict(self) -> dict:
210
+ """Serialize Cluster to dictionary."""
211
+ return {
212
+ "id": self.id,
213
+ "name": self.name,
214
+ "purpose": self.purpose,
215
+ "description": self.description,
216
+ "status": self.status.value,
217
+ "progress": self.progress(),
218
+ "blocks": [b.to_dict() for b in self.blocks.values()],
219
+ "io_tower_checkpoints": self.io_tower_checkpoints,
220
+ "total_threads": self.total_threads(),
221
+ "completed_threads": self.completed_threads(),
222
+ "created_at": self.created_at.isoformat(),
223
+ "started_at": self.started_at.isoformat() if self.started_at else None,
224
+ "completed_at": self.completed_at.isoformat() if self.completed_at else None,
225
+ }
226
+
227
+ def __repr__(self) -> str:
228
+ return f"Cluster(id={self.id}, name={self.name}, blocks={len(self.blocks)})"
package/core/disc.py ADDED
@@ -0,0 +1,254 @@
1
+ """
2
+ Identity Disc - Carries a Program's memory and decisions.
3
+
4
+ "Everything you do or learn will be imprinted on this disc."
5
+ """
6
+
7
+ from dataclasses import dataclass, field
8
+ from datetime import datetime
9
+ from typing import Optional, Any
10
+ from enum import Enum
11
+ import json
12
+ import uuid
13
+
14
+
15
+ class DiscStatus(Enum):
16
+ """Status of an Identity Disc."""
17
+ ACTIVE = "active"
18
+ ARCHIVED = "archived"
19
+ DEREZZED = "derezzed"
20
+
21
+
22
+ @dataclass
23
+ class Decision:
24
+ """A recorded decision made by a Program."""
25
+ timestamp: datetime
26
+ choice: str
27
+ reasoning: str
28
+ alternatives: list[str] = field(default_factory=list)
29
+
30
+ def to_dict(self) -> dict:
31
+ return {
32
+ "timestamp": self.timestamp.isoformat(),
33
+ "choice": self.choice,
34
+ "reasoning": self.reasoning,
35
+ "alternatives": self.alternatives,
36
+ }
37
+
38
+
39
+ @dataclass
40
+ class Discovery:
41
+ """Something learned during execution."""
42
+ timestamp: datetime
43
+ finding: str
44
+ source: str
45
+ relevance: str = "medium" # low, medium, high, critical
46
+
47
+ def to_dict(self) -> dict:
48
+ return {
49
+ "timestamp": self.timestamp.isoformat(),
50
+ "finding": self.finding,
51
+ "source": self.source,
52
+ "relevance": self.relevance,
53
+ }
54
+
55
+
56
+ @dataclass
57
+ class Artifact:
58
+ """A file or resource created/modified by a Program."""
59
+ path: str
60
+ action: str # created, modified, deleted
61
+ timestamp: datetime
62
+ description: str = ""
63
+
64
+ def to_dict(self) -> dict:
65
+ return {
66
+ "path": self.path,
67
+ "action": self.action,
68
+ "timestamp": self.timestamp.isoformat(),
69
+ "description": self.description,
70
+ }
71
+
72
+
73
+ class IdentityDisc:
74
+ """
75
+ The Identity Disc - carries a Program's memory and decisions.
76
+
77
+ Each Program on The Grid carries an Identity Disc containing:
78
+ - Purpose: What the Program is trying to accomplish
79
+ - Constraints: Boundaries it must respect
80
+ - Decisions: Choices made and why
81
+ - Discoveries: Things learned during execution
82
+ - Artifacts: Files created/modified
83
+ - Lineage: Parent/child relationships for fission
84
+ """
85
+
86
+ def __init__(
87
+ self,
88
+ program_id: str,
89
+ purpose: str = "",
90
+ parent_disc: Optional["IdentityDisc"] = None,
91
+ ):
92
+ self.id = str(uuid.uuid4())[:8]
93
+ self.program_id = program_id
94
+ self.created_at = datetime.now()
95
+ self.status = DiscStatus.ACTIVE
96
+
97
+ # Core identity
98
+ self.purpose = purpose
99
+ self.constraints: list[str] = []
100
+
101
+ # Memory
102
+ self.decisions: list[Decision] = []
103
+ self.discoveries: list[Discovery] = []
104
+ self.artifacts: list[Artifact] = []
105
+
106
+ # Lineage (for fission)
107
+ self.parent_disc = parent_disc
108
+ self.child_discs: list["IdentityDisc"] = []
109
+ self.depth = 0 if parent_disc is None else parent_disc.depth + 1
110
+
111
+ # Energy tracking
112
+ self.energy_allocated = 0
113
+ self.energy_consumed = 0
114
+
115
+ # Inherit relevant context from parent
116
+ if parent_disc:
117
+ self._inherit_from_parent(parent_disc)
118
+
119
+ def _inherit_from_parent(self, parent: "IdentityDisc") -> None:
120
+ """Inherit relevant context from parent disc."""
121
+ # Inherit constraints
122
+ self.constraints = parent.constraints.copy()
123
+
124
+ # Inherit high-relevance discoveries
125
+ for discovery in parent.discoveries:
126
+ if discovery.relevance in ("high", "critical"):
127
+ self.discoveries.append(discovery)
128
+
129
+ # Register as child of parent
130
+ parent.child_discs.append(self)
131
+
132
+ def record_decision(
133
+ self,
134
+ choice: str,
135
+ reasoning: str,
136
+ alternatives: list[str] = None,
137
+ ) -> Decision:
138
+ """Record a decision made by the Program."""
139
+ decision = Decision(
140
+ timestamp=datetime.now(),
141
+ choice=choice,
142
+ reasoning=reasoning,
143
+ alternatives=alternatives or [],
144
+ )
145
+ self.decisions.append(decision)
146
+ return decision
147
+
148
+ def record_discovery(
149
+ self,
150
+ finding: str,
151
+ source: str,
152
+ relevance: str = "medium",
153
+ ) -> Discovery:
154
+ """Record something learned during execution."""
155
+ discovery = Discovery(
156
+ timestamp=datetime.now(),
157
+ finding=finding,
158
+ source=source,
159
+ relevance=relevance,
160
+ )
161
+ self.discoveries.append(discovery)
162
+ return discovery
163
+
164
+ def record_artifact(
165
+ self,
166
+ path: str,
167
+ action: str,
168
+ description: str = "",
169
+ ) -> Artifact:
170
+ """Record a file/resource created or modified."""
171
+ artifact = Artifact(
172
+ path=path,
173
+ action=action,
174
+ timestamp=datetime.now(),
175
+ description=description,
176
+ )
177
+ self.artifacts.append(artifact)
178
+ return artifact
179
+
180
+ def add_constraint(self, constraint: str) -> None:
181
+ """Add a constraint the Program must respect."""
182
+ if constraint not in self.constraints:
183
+ self.constraints.append(constraint)
184
+
185
+ def consume_energy(self, amount: int) -> bool:
186
+ """Consume energy. Returns False if insufficient energy."""
187
+ if self.energy_consumed + amount > self.energy_allocated:
188
+ return False
189
+ self.energy_consumed += amount
190
+ return True
191
+
192
+ def energy_remaining(self) -> int:
193
+ """Get remaining energy."""
194
+ return self.energy_allocated - self.energy_consumed
195
+
196
+ def energy_percentage(self) -> float:
197
+ """Get energy as percentage of allocated."""
198
+ if self.energy_allocated == 0:
199
+ return 0.0
200
+ return (self.energy_remaining() / self.energy_allocated) * 100
201
+
202
+ def derez(self) -> None:
203
+ """Mark disc as derezzed (completed/archived)."""
204
+ self.status = DiscStatus.DEREZZED
205
+
206
+ def get_lineage(self) -> list[str]:
207
+ """Get the lineage chain of program IDs."""
208
+ lineage = [self.program_id]
209
+ current = self.parent_disc
210
+ while current:
211
+ lineage.insert(0, current.program_id)
212
+ current = current.parent_disc
213
+ return lineage
214
+
215
+ def to_dict(self) -> dict:
216
+ """Serialize disc to dictionary."""
217
+ return {
218
+ "id": self.id,
219
+ "program_id": self.program_id,
220
+ "created_at": self.created_at.isoformat(),
221
+ "status": self.status.value,
222
+ "purpose": self.purpose,
223
+ "constraints": self.constraints,
224
+ "decisions": [d.to_dict() for d in self.decisions],
225
+ "discoveries": [d.to_dict() for d in self.discoveries],
226
+ "artifacts": [a.to_dict() for a in self.artifacts],
227
+ "depth": self.depth,
228
+ "lineage": self.get_lineage(),
229
+ "energy_allocated": self.energy_allocated,
230
+ "energy_consumed": self.energy_consumed,
231
+ "child_count": len(self.child_discs),
232
+ }
233
+
234
+ def to_json(self) -> str:
235
+ """Serialize disc to JSON."""
236
+ return json.dumps(self.to_dict(), indent=2)
237
+
238
+ def summary(self) -> str:
239
+ """Get a brief summary of the disc contents."""
240
+ lines = [
241
+ f"Identity Disc [{self.id}]",
242
+ f" Program: {self.program_id}",
243
+ f" Purpose: {self.purpose}",
244
+ f" Depth: {self.depth}",
245
+ f" Energy: {self.energy_remaining()}/{self.energy_allocated}",
246
+ f" Decisions: {len(self.decisions)}",
247
+ f" Discoveries: {len(self.discoveries)}",
248
+ f" Artifacts: {len(self.artifacts)}",
249
+ f" Children: {len(self.child_discs)}",
250
+ ]
251
+ return "\n".join(lines)
252
+
253
+ def __repr__(self) -> str:
254
+ return f"IdentityDisc(id={self.id}, program={self.program_id}, depth={self.depth})"