algo-cli-runtime 0.14.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.
Files changed (237) hide show
  1. algo_cli/__init__.py +3 -0
  2. algo_cli/__main__.py +7 -0
  3. algo_cli/_internal/__init__.py +12 -0
  4. algo_cli/_internal/policy_chain.py +259 -0
  5. algo_cli/action_registry.py +1047 -0
  6. algo_cli/agent_blocks.py +550 -0
  7. algo_cli/agent_pipeline.py +1457 -0
  8. algo_cli/agent_threads.py +308 -0
  9. algo_cli/animations.py +316 -0
  10. algo_cli/cache_admission.py +209 -0
  11. algo_cli/capability_mask.py +66 -0
  12. algo_cli/chat_protocol.py +116 -0
  13. algo_cli/chatgpt_auth.py +510 -0
  14. algo_cli/chatgpt_client.py +657 -0
  15. algo_cli/code_rag.py +479 -0
  16. algo_cli/config.py +651 -0
  17. algo_cli/context_budget.py +679 -0
  18. algo_cli/credential_helpers.py +315 -0
  19. algo_cli/deliberation.py +29 -0
  20. algo_cli/display.py +1470 -0
  21. algo_cli/evals/__init__.py +21 -0
  22. algo_cli/evals/algorithm_effectiveness.py +560 -0
  23. algo_cli/evals/competitive_harness_rating.py +702 -0
  24. algo_cli/evals/cot_quality.py +220 -0
  25. algo_cli/evals/harness_retrieval_benchmark.py +401 -0
  26. algo_cli/evals/performance_regression.py +136 -0
  27. algo_cli/evals/scorecard_grading.py +308 -0
  28. algo_cli/evals/session_distribution.py +84 -0
  29. algo_cli/execution_guardrails.py +806 -0
  30. algo_cli/extensions_manifest.py +84 -0
  31. algo_cli/git_evidence.py +227 -0
  32. algo_cli/google_workspace.py +407 -0
  33. algo_cli/google_workspace_auth.py +523 -0
  34. algo_cli/harness.py +2587 -0
  35. algo_cli/identity.py +557 -0
  36. algo_cli/index_compute_lab.py +228 -0
  37. algo_cli/inference_harness.py +70 -0
  38. algo_cli/intelligence/__init__.py +1103 -0
  39. algo_cli/intelligence/acrobat_config.py +307 -0
  40. algo_cli/intelligence/acrobat_manifests.py +338 -0
  41. algo_cli/intelligence/acrobat_models.py +195 -0
  42. algo_cli/intelligence/acrobat_pipeline.py +295 -0
  43. algo_cli/intelligence/acrobat_runtime.py +302 -0
  44. algo_cli/intelligence/acrobat_security.py +261 -0
  45. algo_cli/intelligence/acrobat_workflows.py +226 -0
  46. algo_cli/intelligence/actionability.py +165 -0
  47. algo_cli/intelligence/adversarial_audit.py +136 -0
  48. algo_cli/intelligence/agent_arena.py +92 -0
  49. algo_cli/intelligence/agent_benchmark.py +236 -0
  50. algo_cli/intelligence/agent_runtime.py +171 -0
  51. algo_cli/intelligence/agents_as_tools.py +70 -0
  52. algo_cli/intelligence/artifact_binding.py +80 -0
  53. algo_cli/intelligence/autonomous_engineer.py +1976 -0
  54. algo_cli/intelligence/backpressure.py +99 -0
  55. algo_cli/intelligence/bloom_filter.py +186 -0
  56. algo_cli/intelligence/bonferroni.py +66 -0
  57. algo_cli/intelligence/boundary_compaction.py +98 -0
  58. algo_cli/intelligence/catalog_verifier.py +172 -0
  59. algo_cli/intelligence/cavecrew.py +118 -0
  60. algo_cli/intelligence/changelog.py +176 -0
  61. algo_cli/intelligence/checkpoint_resume.py +92 -0
  62. algo_cli/intelligence/circuit_breaker.py +88 -0
  63. algo_cli/intelligence/clarification_gate.py +101 -0
  64. algo_cli/intelligence/code_graph.py +180 -0
  65. algo_cli/intelligence/coderank.py +97 -0
  66. algo_cli/intelligence/consistent_hash.py +150 -0
  67. algo_cli/intelligence/consortium_synthesis.py +139 -0
  68. algo_cli/intelligence/construction/__init__.py +241 -0
  69. algo_cli/intelligence/construction/common.py +273 -0
  70. algo_cli/intelligence/construction/documents.py +496 -0
  71. algo_cli/intelligence/construction/labor_units.py +1395 -0
  72. algo_cli/intelligence/construction/payments.py +470 -0
  73. algo_cli/intelligence/construction/risk.py +784 -0
  74. algo_cli/intelligence/content_extractor.py +132 -0
  75. algo_cli/intelligence/context_adaptive.py +102 -0
  76. algo_cli/intelligence/context_ops.py +95 -0
  77. algo_cli/intelligence/count_min.py +145 -0
  78. algo_cli/intelligence/cow_state.py +103 -0
  79. algo_cli/intelligence/critic_loop.py +119 -0
  80. algo_cli/intelligence/cross_source.py +113 -0
  81. algo_cli/intelligence/daemon_mode.py +99 -0
  82. algo_cli/intelligence/dag_orchestration.py +151 -0
  83. algo_cli/intelligence/deep_research.py +155 -0
  84. algo_cli/intelligence/degenerate_detector.py +78 -0
  85. algo_cli/intelligence/delta_report.py +92 -0
  86. algo_cli/intelligence/discovery_event_log.py +92 -0
  87. algo_cli/intelligence/document_ingest.py +298 -0
  88. algo_cli/intelligence/dual_layer_validate.py +151 -0
  89. algo_cli/intelligence/echo_fidelity.py +73 -0
  90. algo_cli/intelligence/ema_tuning.py +104 -0
  91. algo_cli/intelligence/event_log.py +92 -0
  92. algo_cli/intelligence/evidence_graph.py +114 -0
  93. algo_cli/intelligence/extension_host.py +162 -0
  94. algo_cli/intelligence/extension_manifest.py +115 -0
  95. algo_cli/intelligence/falsification_suite.py +178 -0
  96. algo_cli/intelligence/finance/__init__.py +169 -0
  97. algo_cli/intelligence/finance/anomalies.py +135 -0
  98. algo_cli/intelligence/finance/ap_ar.py +351 -0
  99. algo_cli/intelligence/finance/cash.py +162 -0
  100. algo_cli/intelligence/finance/close.py +332 -0
  101. algo_cli/intelligence/finance/common.py +244 -0
  102. algo_cli/intelligence/finance/construction.py +135 -0
  103. algo_cli/intelligence/finance/controls.py +172 -0
  104. algo_cli/intelligence/finance/evidence.py +119 -0
  105. algo_cli/intelligence/finance/exceptions.py +157 -0
  106. algo_cli/intelligence/finance/reconciliations.py +254 -0
  107. algo_cli/intelligence/finance/revenue.py +109 -0
  108. algo_cli/intelligence/finance/tax.py +74 -0
  109. algo_cli/intelligence/finance/workpapers.py +111 -0
  110. algo_cli/intelligence/finding_record.py +120 -0
  111. algo_cli/intelligence/flow_dag.py +267 -0
  112. algo_cli/intelligence/gatherer.py +223 -0
  113. algo_cli/intelligence/golden_master.py +98 -0
  114. algo_cli/intelligence/graph_rag.py +195 -0
  115. algo_cli/intelligence/group_chat.py +143 -0
  116. algo_cli/intelligence/hash_dedup.py +145 -0
  117. algo_cli/intelligence/hyperloglog.py +128 -0
  118. algo_cli/intelligence/incremental_index.py +316 -0
  119. algo_cli/intelligence/index_store.py +16 -0
  120. algo_cli/intelligence/iteration_plan.py +133 -0
  121. algo_cli/intelligence/kernel_plugins.py +167 -0
  122. algo_cli/intelligence/lesson_catalog.py +135 -0
  123. algo_cli/intelligence/llm_fallback.py +169 -0
  124. algo_cli/intelligence/log2_histogram.py +267 -0
  125. algo_cli/intelligence/lsp_integration.py +147 -0
  126. algo_cli/intelligence/memory_evolution.py +117 -0
  127. algo_cli/intelligence/minhash_lsh.py +182 -0
  128. algo_cli/intelligence/multi_model_score.py +174 -0
  129. algo_cli/intelligence/multi_tier_grade.py +211 -0
  130. algo_cli/intelligence/negative_controls.py +113 -0
  131. algo_cli/intelligence/numeric_clamp.py +63 -0
  132. algo_cli/intelligence/occ_editor.py +66 -0
  133. algo_cli/intelligence/output_normalize.py +112 -0
  134. algo_cli/intelligence/parallel_delegation.py +98 -0
  135. algo_cli/intelligence/parallel_fanout.py +104 -0
  136. algo_cli/intelligence/permission_modes.py +105 -0
  137. algo_cli/intelligence/pre_push_gate.py +68 -0
  138. algo_cli/intelligence/prefetch.py +171 -0
  139. algo_cli/intelligence/process_framework.py +217 -0
  140. algo_cli/intelligence/project_graph.py +387 -0
  141. algo_cli/intelligence/query_expansion.py +146 -0
  142. algo_cli/intelligence/ralph_loop.py +117 -0
  143. algo_cli/intelligence/rate_limiter.py +153 -0
  144. algo_cli/intelligence/refactor_transaction.py +94 -0
  145. algo_cli/intelligence/research_workspace.py +108 -0
  146. algo_cli/intelligence/retraction_ledger.py +72 -0
  147. algo_cli/intelligence/saga_pattern.py +88 -0
  148. algo_cli/intelligence/session_fork.py +100 -0
  149. algo_cli/intelligence/shadow_editor.py +67 -0
  150. algo_cli/intelligence/shell_session.py +213 -0
  151. algo_cli/intelligence/source_registry.py +143 -0
  152. algo_cli/intelligence/spawn_scales.py +99 -0
  153. algo_cli/intelligence/stat_stability.py +104 -0
  154. algo_cli/intelligence/structural_validator.py +148 -0
  155. algo_cli/intelligence/subagent_spawner.py +111 -0
  156. algo_cli/intelligence/symmetric_verify.py +70 -0
  157. algo_cli/intelligence/task_classifier.py +129 -0
  158. algo_cli/intelligence/team_execution.py +122 -0
  159. algo_cli/intelligence/tiered_access.py +121 -0
  160. algo_cli/intelligence/utility_registry.py +159 -0
  161. algo_cli/intuition_engine.py +560 -0
  162. algo_cli/intuition_injector.py +82 -0
  163. algo_cli/kernels/__init__.py +5 -0
  164. algo_cli/kernels/manifest.py +763 -0
  165. algo_cli/main.py +3903 -0
  166. algo_cli/memory_candidates.py +541 -0
  167. algo_cli/memory_echo_veil.py +394 -0
  168. algo_cli/memory_runtime.py +112 -0
  169. algo_cli/model_info.py +548 -0
  170. algo_cli/model_profile.py +160 -0
  171. algo_cli/model_routing.py +74 -0
  172. algo_cli/oneshot.py +331 -0
  173. algo_cli/perf_telemetry.py +389 -0
  174. algo_cli/plugins.py +245 -0
  175. algo_cli/private_event_store.py +654 -0
  176. algo_cli/quantization/__init__.py +24 -0
  177. algo_cli/quantization/lloyd_max.py +98 -0
  178. algo_cli/quantization/turbo_quant.py +308 -0
  179. algo_cli/reasoning/__init__.py +46 -0
  180. algo_cli/reasoning/combinatorial.py +356 -0
  181. algo_cli/reasoning/graph_of_thought.py +297 -0
  182. algo_cli/reasoning/mcts.py +220 -0
  183. algo_cli/reasoning/neuro_symbolic.py +250 -0
  184. algo_cli/reasoning/react.py +246 -0
  185. algo_cli/reasoning/reflexion.py +225 -0
  186. algo_cli/reasoning/tree_of_thought.py +241 -0
  187. algo_cli/reasoning_bridge.py +150 -0
  188. algo_cli/reconciliation.py +284 -0
  189. algo_cli/reflex.py +385 -0
  190. algo_cli/resources/docs/ALGO.md +13958 -0
  191. algo_cli/resources/docs/algo-cli-algorithm-evidence-contract.md +60 -0
  192. algo_cli/resources/docs/algo-cli-execution-verification-contract.md +59 -0
  193. algo_cli/resources/docs/algo-cli-memory-lifecycle-contract.md +72 -0
  194. algo_cli/resources/docs/harness-extension-cleanup-recommendation.md +41 -0
  195. algo_cli/resources/docs/index-compute-lab-integration.md +32 -0
  196. algo_cli/resources/docs/inference-harness-loop-blueprint-2026-06.md +55 -0
  197. algo_cli/resources/docs/main-split-map.md +35 -0
  198. algo_cli/resources/docs/privacy-and-context.md +48 -0
  199. algo_cli/resources/docs/reflex-loop-v0.2.md +354 -0
  200. algo_cli/resources/skills/README.md +26 -0
  201. algo_cli/resources/skills/algo-cli.md +59 -0
  202. algo_cli/resources/skills/edit-file-precision.md +49 -0
  203. algo_cli/resources/skills/harness-search-first.md +47 -0
  204. algo_cli/resources/skills/memory-recall-ritual.md +51 -0
  205. algo_cli/resources/skills/qol-algorithms.md +224 -0
  206. algo_cli/resources/skills/smart-error-recovery.md +56 -0
  207. algo_cli/resources/skills/tool-selection-cheatsheet.md +65 -0
  208. algo_cli/retrieval_algorithms.py +127 -0
  209. algo_cli/runtime_qos.py +236 -0
  210. algo_cli/runtime_services.py +320 -0
  211. algo_cli/session_commands.py +95 -0
  212. algo_cli/session_mode.py +113 -0
  213. algo_cli/skills.py +430 -0
  214. algo_cli/slash_dispatch.py +1265 -0
  215. algo_cli/small_context.py +206 -0
  216. algo_cli/spawn_budget.py +89 -0
  217. algo_cli/task_ledger.py +84 -0
  218. algo_cli/task_router.py +197 -0
  219. algo_cli/tool_context.py +94 -0
  220. algo_cli/tool_contract.py +99 -0
  221. algo_cli/tool_policy.py +357 -0
  222. algo_cli/tool_runtime.py +647 -0
  223. algo_cli/tools.py +3056 -0
  224. algo_cli/url_scheme.py +174 -0
  225. algo_cli/verify.py +154 -0
  226. algo_cli/version_manifest.py +178 -0
  227. algo_cli/vision_screenshot_verify.py +76 -0
  228. algo_cli/workspace_resolver.py +68 -0
  229. algo_cli/x_account.py +209 -0
  230. algo_cli/xai_auth.py +374 -0
  231. algo_cli/xai_client.py +600 -0
  232. algo_cli_runtime-0.14.0.dist-info/METADATA +369 -0
  233. algo_cli_runtime-0.14.0.dist-info/RECORD +237 -0
  234. algo_cli_runtime-0.14.0.dist-info/WHEEL +4 -0
  235. algo_cli_runtime-0.14.0.dist-info/entry_points.txt +3 -0
  236. algo_cli_runtime-0.14.0.dist-info/licenses/LICENSE +21 -0
  237. ollama_cli/__init__.py +67 -0
@@ -0,0 +1,213 @@
1
+ """B41. Pseudoterminal Boundary + VT Parser/Emitter (Windows Terminal Pattern).
2
+
3
+ Wraps shell command execution with a session abstraction: process boundary,
4
+ streaming stdout/stderr frames, ANSI/VT normalization, command replay
5
+ metadata, and timeout/cancellation.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import re
11
+ import time
12
+ import uuid
13
+ from dataclasses import dataclass, field
14
+ from typing import Any
15
+
16
+
17
+ # ── ANSI/VT normalization ─────────────────────────────────────────────
18
+
19
+ # Match ANSI escape sequences
20
+ _ANSI_RE = re.compile(r"\x1b\[[0-9;]*[a-zA-Z]")
21
+ # Match other control chars (except \n, \r, \t)
22
+ _CTRL_RE = re.compile(r"[\x00-\x08\x0b\x0c\x0e-\x1f]")
23
+
24
+
25
+ def strip_ansi(text: str) -> str:
26
+ """Remove ANSI escape sequences."""
27
+ return _ANSI_RE.sub("", text)
28
+
29
+
30
+ def normalize_vt(text: str) -> str:
31
+ """Remove ANSI escapes and control characters, keep newlines/tabs."""
32
+ text = _ANSI_RE.sub("", text)
33
+ text = _CTRL_RE.sub("", text)
34
+ return text
35
+
36
+
37
+ def has_ansi(text: str) -> bool:
38
+ """Check if text contains ANSI escape sequences."""
39
+ return bool(_ANSI_RE.search(text))
40
+
41
+
42
+ # ── streaming frames ──────────────────────────────────────────────────
43
+
44
+
45
+ @dataclass
46
+ class OutputFrame:
47
+ """A single chunk of process output."""
48
+ stream: str # "stdout" or "stderr"
49
+ data: str
50
+ raw_bytes: bytes = b""
51
+ timestamp: float = field(default_factory=time.time)
52
+ frame_index: int = 0
53
+
54
+
55
+ @dataclass
56
+ class CommandRecord:
57
+ """Metadata for a executed command (for replay)."""
58
+ id: str
59
+ command: str
60
+ cwd: str = ""
61
+ started_at: float = field(default_factory=time.time)
62
+ finished_at: float | None = None
63
+ exit_code: int | None = None
64
+ frames: list[OutputFrame] = field(default_factory=list)
65
+ cancelled: bool = False
66
+ timeout_hit: bool = False
67
+
68
+ @property
69
+ def duration_ms(self) -> float:
70
+ end = self.finished_at or time.time()
71
+ return (end - self.started_at) * 1000
72
+
73
+ @property
74
+ def raw_output(self) -> str:
75
+ """Raw output with ANSI preserved."""
76
+ return "".join(f.data for f in self.frames)
77
+
78
+ @property
79
+ def normalized_output(self) -> str:
80
+ """Output with ANSI/control chars stripped."""
81
+ return normalize_vt(self.raw_output)
82
+
83
+ @property
84
+ def stdout(self) -> str:
85
+ return normalize_vt("".join(f.data for f in self.frames if f.stream == "stdout"))
86
+
87
+ @property
88
+ def stderr(self) -> str:
89
+ return normalize_vt("".join(f.data for f in self.frames if f.stream == "stderr"))
90
+
91
+
92
+ # ── shell session ─────────────────────────────────────────────────────
93
+
94
+
95
+ class ShellSession:
96
+ """Pseudoterminal boundary for shell command execution.
97
+
98
+ Wraps subprocess execution with:
99
+ - streaming output frames
100
+ - raw + normalized output preservation
101
+ - timeout/cancellation
102
+ - command replay metadata
103
+ - ANSI/VT normalization
104
+ """
105
+
106
+ def __init__(self, cwd: str = "", default_timeout: int = 120):
107
+ self.cwd = cwd
108
+ self.default_timeout = default_timeout
109
+ self.history: list[CommandRecord] = []
110
+ self._cancelled_ids: set[str] = set()
111
+
112
+ def execute(self, command: str, timeout: int | None = None) -> CommandRecord:
113
+ """Execute a command and return its record.
114
+
115
+ This is a synchronous wrapper. For real streaming, use execute_streaming.
116
+ """
117
+ import subprocess
118
+
119
+ rec = CommandRecord(id=str(uuid.uuid4()), command=command, cwd=self.cwd)
120
+ effective_timeout = timeout or self.default_timeout
121
+
122
+ try:
123
+ proc = subprocess.run(
124
+ command,
125
+ cwd=self.cwd or None,
126
+ capture_output=True,
127
+ text=True,
128
+ timeout=effective_timeout,
129
+ shell=True,
130
+ )
131
+ rec.frames.append(OutputFrame(
132
+ stream="stdout", data=proc.stdout,
133
+ raw_bytes=proc.stdout.encode("utf-8", errors="replace"),
134
+ frame_index=0,
135
+ ))
136
+ rec.frames.append(OutputFrame(
137
+ stream="stderr", data=proc.stderr,
138
+ raw_bytes=proc.stderr.encode("utf-8", errors="replace"),
139
+ frame_index=1,
140
+ ))
141
+ rec.exit_code = proc.returncode
142
+ rec.finished_at = time.time()
143
+ except subprocess.TimeoutExpired as e:
144
+ rec.timeout_hit = True
145
+ rec.exit_code = -1
146
+ rec.finished_at = time.time()
147
+ if e.stdout:
148
+ rec.frames.append(OutputFrame(stream="stdout", data=e.stdout.decode("utf-8", errors="replace") if isinstance(e.stdout, bytes) else str(e.stdout), frame_index=0))
149
+ if e.stderr:
150
+ rec.frames.append(OutputFrame(stream="stderr", data=e.stderr.decode("utf-8", errors="replace") if isinstance(e.stderr, bytes) else str(e.stderr), frame_index=1))
151
+ except Exception as e:
152
+ rec.exit_code = -1
153
+ rec.finished_at = time.time()
154
+ rec.frames.append(OutputFrame(stream="stderr", data=str(e), frame_index=0))
155
+
156
+ self.history.append(rec)
157
+ return rec
158
+
159
+ def cancel(self, command_id: str) -> None:
160
+ """Mark a command as cancelled (for async execution)."""
161
+ self._cancelled_ids.add(command_id)
162
+
163
+ def is_cancelled(self, command_id: str) -> bool:
164
+ return command_id in self._cancelled_ids
165
+
166
+ def replay(self, command_id: str) -> CommandRecord | None:
167
+ """Get a past command record for replay/inspection."""
168
+ for rec in self.history:
169
+ if rec.id == command_id:
170
+ return rec
171
+ return None
172
+
173
+ def recent(self, n: int = 10) -> list[CommandRecord]:
174
+ """Get the N most recent command records."""
175
+ return self.history[-n:]
176
+
177
+ def stats(self) -> dict[str, Any]:
178
+ total = len(self.history)
179
+ succeeded = sum(1 for r in self.history if r.exit_code == 0)
180
+ failed = sum(1 for r in self.history if r.exit_code is not None and r.exit_code != 0)
181
+ timeouts = sum(1 for r in self.history if r.timeout_hit)
182
+ return {
183
+ "total": total,
184
+ "succeeded": succeeded,
185
+ "failed": failed,
186
+ "timeouts": timeouts,
187
+ "avg_duration_ms": sum(r.duration_ms for r in self.history) / max(total, 1),
188
+ }
189
+
190
+
191
+ # ── shell guardrail parser ────────────────────────────────────────────
192
+
193
+
194
+ _BLOCKED_PATTERNS = [
195
+ (r"<<\s*['\"]?EOF", "heredoc not supported in cmd.exe"),
196
+ (r"<<\s*['\"]?PY", "heredoc not supported in cmd.exe"),
197
+ (r"python\s+-c\s+\"[^\"]*\\n", "literal \\n in python -c not supported in cmd.exe"),
198
+ (r"\bcat\s+<<", "cat heredoc not supported in cmd.exe"),
199
+ ]
200
+
201
+
202
+ def check_shell_safety(command: str, shell: str = "cmd") -> list[str]:
203
+ """Check a command for shell-specific safety issues.
204
+
205
+ Returns a list of warning strings (empty if safe).
206
+ """
207
+ if shell != "cmd":
208
+ return []
209
+ warnings: list[str] = []
210
+ for pattern, message in _BLOCKED_PATTERNS:
211
+ if re.search(pattern, command):
212
+ warnings.append(message)
213
+ return warnings
@@ -0,0 +1,143 @@
1
+ """B42. Source Registry + Policy-Aware Resolution (WinGet Pattern).
2
+
3
+ Manages multiple harness/plugin/model/document sources with priority,
4
+ trust levels, enabled flags, and policy locks. Higher-priority trusted
5
+ sources win resolution conflicts.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass, field
11
+ from datetime import datetime
12
+ from typing import Any
13
+
14
+
15
+ class SourceType:
16
+ HARNESS = "harness"
17
+ PLUGIN = "plugin"
18
+ MODEL = "model"
19
+ DOCUMENT = "document"
20
+ PROJECT = "project"
21
+ KNOWLEDGE_GRAPH = "knowledge_graph"
22
+
23
+
24
+ @dataclass
25
+ class Source:
26
+ """A registered content source."""
27
+
28
+ source_id: str
29
+ source_type: str
30
+ path: str = ""
31
+ priority: int = 100 # lower = higher priority
32
+ trust_level: str = "trusted" # "trusted", "untrusted", "blocked"
33
+ enabled: bool = True
34
+ last_refresh: str = ""
35
+ policy_locked: bool = False
36
+ metadata: dict[str, Any] = field(default_factory=dict)
37
+
38
+ def can_resolve(self) -> bool:
39
+ return self.enabled and self.trust_level != "blocked"
40
+
41
+
42
+ @dataclass
43
+ class SourceRecord:
44
+ """A record retrieved from a source, with provenance."""
45
+ source_id: str
46
+ record_id: str
47
+ content: Any
48
+ trust_level: str = "trusted"
49
+
50
+
51
+ class SourceRegistry:
52
+ """Policy-aware source registry with priority resolution."""
53
+
54
+ def __init__(self) -> None:
55
+ self._sources: dict[str, Source] = {}
56
+
57
+ def add(self, source: Source) -> None:
58
+ self._sources[source.source_id] = source
59
+
60
+ def remove(self, source_id: str) -> bool:
61
+ return self._sources.pop(source_id, None) is not None
62
+
63
+ def get(self, source_id: str) -> Source | None:
64
+ return self._sources.get(source_id)
65
+
66
+ def list_all(self) -> list[Source]:
67
+ return list(self._sources.values())
68
+
69
+ def list_enabled(self) -> list[Source]:
70
+ return [s for s in self._sources.values() if s.enabled]
71
+
72
+ def list_by_type(self, source_type: str) -> list[Source]:
73
+ return [s for s in self._sources.values() if s.source_type == source_type]
74
+
75
+ def resolve(self, record_id: str, candidates: list[SourceRecord]) -> SourceRecord | None:
76
+ """Resolve a record from multiple sources by priority/trust.
77
+
78
+ Higher-priority (lower number) trusted sources win.
79
+ """
80
+ enabled_sources = {s.source_id: s for s in self._sources.values() if s.can_resolve()}
81
+ best: SourceRecord | None = None
82
+ best_priority = 999
83
+ for rec in candidates:
84
+ src = enabled_sources.get(rec.source_id)
85
+ if not src:
86
+ continue
87
+ if src.priority < best_priority:
88
+ best = rec
89
+ best_priority = src.priority
90
+ return best
91
+
92
+ def disable(self, source_id: str) -> bool:
93
+ src = self._sources.get(source_id)
94
+ if src and not src.policy_locked:
95
+ src.enabled = False
96
+ return True
97
+ return False
98
+
99
+ def enable(self, source_id: str) -> bool:
100
+ src = self._sources.get(source_id)
101
+ if src:
102
+ src.enabled = True
103
+ return True
104
+ return False
105
+
106
+ def lock_policy(self, source_id: str) -> bool:
107
+ src = self._sources.get(source_id)
108
+ if src:
109
+ src.policy_locked = True
110
+ return True
111
+ return False
112
+
113
+ def refresh(self, source_id: str) -> bool:
114
+ src = self._sources.get(source_id)
115
+ if src:
116
+ src.last_refresh = datetime.now().isoformat()
117
+ return True
118
+ return False
119
+
120
+ def health(self) -> list[dict[str, Any]]:
121
+ return [
122
+ {
123
+ "source_id": s.source_id,
124
+ "type": s.source_type,
125
+ "enabled": s.enabled,
126
+ "trust": s.trust_level,
127
+ "priority": s.priority,
128
+ "last_refresh": s.last_refresh,
129
+ "policy_locked": s.policy_locked,
130
+ }
131
+ for s in self._sources.values()
132
+ ]
133
+
134
+ def conflicts(self) -> list[dict[str, Any]]:
135
+ """Detect sources with same type and priority."""
136
+ by_key: dict[tuple[str, int], list[str]] = {}
137
+ for s in self._sources.values():
138
+ key = (s.source_type, s.priority)
139
+ by_key.setdefault(key, []).append(s.source_id)
140
+ return [
141
+ {"type": k[0], "priority": k[1], "sources": v}
142
+ for k, v in by_key.items() if len(v) > 1
143
+ ]
@@ -0,0 +1,99 @@
1
+ """B76. Three Scales of Spawning.
2
+
3
+ Virtual File (2-4 agents) → Git Worktree (10-100) → Cloud Worker (100+).
4
+ Source: awesome-agentic-patterns.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from dataclasses import dataclass
9
+ from enum import Enum, auto
10
+ from typing import Any
11
+
12
+
13
+ class SpawnScale(Enum):
14
+ VIRTUAL_FILE = auto() # 2-4 agents, in-memory isolation
15
+ GIT_WORKTREE = auto() # 10-100 agents, filesystem isolation
16
+ CLOUD_WORKER = auto() # 100+ agents, container isolation
17
+
18
+
19
+ @dataclass
20
+ class ScaleConfig:
21
+ scale: SpawnScale
22
+ max_agents: int
23
+ isolation_level: str # "memory", "filesystem", "container"
24
+ cost_per_agent: float # relative cost
25
+ setup_time_s: float # time to spawn one agent
26
+ cleanup_required: bool
27
+
28
+
29
+ DEFAULT_CONFIGS: dict[SpawnScale, ScaleConfig] = {
30
+ SpawnScale.VIRTUAL_FILE: ScaleConfig(
31
+ scale=SpawnScale.VIRTUAL_FILE,
32
+ max_agents=4,
33
+ isolation_level="memory",
34
+ cost_per_agent=0.1,
35
+ setup_time_s=0.01,
36
+ cleanup_required=False,
37
+ ),
38
+ SpawnScale.GIT_WORKTREE: ScaleConfig(
39
+ scale=SpawnScale.GIT_WORKTREE,
40
+ max_agents=100,
41
+ isolation_level="filesystem",
42
+ cost_per_agent=0.5,
43
+ setup_time_s=0.5,
44
+ cleanup_required=True,
45
+ ),
46
+ SpawnScale.CLOUD_WORKER: ScaleConfig(
47
+ scale=SpawnScale.CLOUD_WORKER,
48
+ max_agents=1000,
49
+ isolation_level="container",
50
+ cost_per_agent=2.0,
51
+ setup_time_s=5.0,
52
+ cleanup_required=True,
53
+ ),
54
+ }
55
+
56
+
57
+ class SpawnScaleSelector:
58
+ """Select the appropriate spawning scale based on requirements."""
59
+
60
+ def select(self, num_agents: int, needs_filesystem: bool = False,
61
+ needs_network: bool = False, budget: float = 1.0) -> SpawnScale:
62
+ """Choose the minimal scale that meets requirements."""
63
+ if num_agents <= 4 and not needs_filesystem and not needs_network:
64
+ return SpawnScale.VIRTUAL_FILE
65
+ if num_agents <= 100 and not needs_network:
66
+ return SpawnScale.GIT_WORKTREE
67
+ return SpawnScale.CLOUD_WORKER
68
+
69
+ def get_config(self, scale: SpawnScale) -> ScaleConfig:
70
+ return DEFAULT_CONFIGS[scale]
71
+
72
+ def estimate_cost(self, scale: SpawnScale, num_agents: int) -> float:
73
+ config = self.get_config(scale)
74
+ return config.cost_per_agent * num_agents
75
+
76
+ def validate(self, scale: SpawnScale, num_agents: int) -> list[str]:
77
+ """Check if the scale can handle the requested agent count."""
78
+ issues: list[str] = []
79
+ config = self.get_config(scale)
80
+ if num_agents > config.max_agents:
81
+ issues.append(f"Too many agents: {num_agents} > {config.max_agents} for {scale.name}")
82
+ return issues
83
+
84
+ def recommend(self, num_agents: int, needs_filesystem: bool = False,
85
+ needs_network: bool = False, budget: float = 1.0) -> dict[str, Any]:
86
+ """Get a recommendation with cost estimate."""
87
+ scale = self.select(num_agents, needs_filesystem, needs_network, budget)
88
+ config = self.get_config(scale)
89
+ cost = self.estimate_cost(scale, num_agents)
90
+ issues = self.validate(scale, num_agents)
91
+
92
+ return {
93
+ "scale": scale.name,
94
+ "isolation": config.isolation_level,
95
+ "estimated_cost": cost,
96
+ "setup_time_s": config.setup_time_s * num_agents,
97
+ "cleanup_required": config.cleanup_required,
98
+ "issues": issues,
99
+ }
@@ -0,0 +1,104 @@
1
+ """H19 — Statistical Stability Guard.
2
+
3
+ Warn when sample sizes are too small for stable results.
4
+ Mined from GLOSSOPETRAE VALIDATION.md D4 (3-seed default yields ±15pt swing).
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import math
9
+ from dataclasses import dataclass
10
+
11
+
12
+ @dataclass
13
+ class StabilityReport:
14
+ """Report on statistical stability of a measurement."""
15
+
16
+ sample_size: int
17
+ mean: float
18
+ std_dev: float
19
+ margin_of_error: float
20
+ confidence_level: float
21
+ is_stable: bool
22
+ recommended_sample_size: int
23
+ warning: str = ""
24
+
25
+ def to_dict(self) -> dict[str, object]:
26
+ return {
27
+ "sample_size": self.sample_size,
28
+ "mean": self.mean,
29
+ "std_dev": self.std_dev,
30
+ "margin_of_error": self.margin_of_error,
31
+ "confidence_level": self.confidence_level,
32
+ "is_stable": self.is_stable,
33
+ "recommended_sample_size": self.recommended_sample_size,
34
+ "warning": self.warning,
35
+ }
36
+
37
+
38
+ # t-distribution critical values (two-tailed, 95% confidence)
39
+ _T_VALUES = {
40
+ 1: 12.706, 2: 4.303, 3: 3.182, 4: 2.776, 5: 2.571,
41
+ 6: 2.447, 7: 2.365, 8: 2.306, 9: 2.262, 10: 2.228,
42
+ 15: 2.131, 20: 2.086, 25: 2.060, 30: 2.042, 40: 2.021,
43
+ 50: 2.009, 100: 1.984, 200: 1.972, float("inf"): 1.960,
44
+ }
45
+
46
+
47
+ def _t_value(df: int) -> float:
48
+ if df in _T_VALUES:
49
+ return _T_VALUES[df]
50
+ if df > 200:
51
+ return _T_VALUES[float("inf")]
52
+ # Find closest key
53
+ closest = min(_T_VALUES.keys(), key=lambda k: abs(k - df) if k != float("inf") else abs(200 - df))
54
+ return _T_VALUES[closest]
55
+
56
+
57
+ class StatisticalStabilityGuard:
58
+ """Check if sample sizes are large enough for stable results."""
59
+
60
+ def __init__(self, target_margin: float = 0.02, confidence: float = 0.95) -> None:
61
+ self.target_margin = target_margin
62
+ self.confidence = confidence
63
+
64
+ def evaluate(self, values: list[float]) -> StabilityReport:
65
+ n = len(values)
66
+ if n == 0:
67
+ return StabilityReport(
68
+ sample_size=0, mean=0.0, std_dev=0.0, margin_of_error=float("inf"),
69
+ confidence_level=self.confidence, is_stable=False,
70
+ recommended_sample_size=1, warning="No samples",
71
+ )
72
+ mean = sum(values) / n
73
+ if n == 1:
74
+ return StabilityReport(
75
+ sample_size=1, mean=mean, std_dev=0.0, margin_of_error=float("inf"),
76
+ confidence_level=self.confidence, is_stable=False,
77
+ recommended_sample_size=30, warning="Single sample — cannot estimate variance",
78
+ )
79
+ variance = sum((v - mean) ** 2 for v in values) / (n - 1)
80
+ std_dev = math.sqrt(variance)
81
+ t = _t_value(n - 1)
82
+ margin = t * std_dev / math.sqrt(n)
83
+ # Recommended sample size for target margin
84
+ if std_dev > 0 and margin > 0:
85
+ recommended = int(math.ceil((t * std_dev / self.target_margin) ** 2))
86
+ else:
87
+ recommended = n
88
+ is_stable = margin <= self.target_margin
89
+ warning = ""
90
+ if not is_stable:
91
+ warning = (
92
+ f"Margin of error {margin:.4f} exceeds target {self.target_margin:.4f}. "
93
+ f"Need ~{recommended} samples (have {n})."
94
+ )
95
+ return StabilityReport(
96
+ sample_size=n,
97
+ mean=mean,
98
+ std_dev=std_dev,
99
+ margin_of_error=margin,
100
+ confidence_level=self.confidence,
101
+ is_stable=is_stable,
102
+ recommended_sample_size=max(recommended, n),
103
+ warning=warning,
104
+ )