apsimo 1.3.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 (614) hide show
  1. apsimo/__init__.py +38 -0
  2. apsimo/__main__.py +6 -0
  3. apsimo/agent/__init__.py +6 -0
  4. apsimo/agent/client.py +276 -0
  5. apsimo/agent/models.py +46 -0
  6. apsimo/agents/__init__.py +20 -0
  7. apsimo/agents/models.py +264 -0
  8. apsimo/agents/store.py +861 -0
  9. apsimo/agents/websocket.py +522 -0
  10. apsimo/api/__init__.py +1 -0
  11. apsimo/api/auth_telemetry.py +287 -0
  12. apsimo/api/authority.py +1203 -0
  13. apsimo/api/contact_grants.py +347 -0
  14. apsimo/api/middleware.py +483 -0
  15. apsimo/api/routers/__init__.py +1 -0
  16. apsimo/api/routers/commitment_work.py +265 -0
  17. apsimo/api/routers/context_gate.py +123 -0
  18. apsimo/api/routers/executions.py +140 -0
  19. apsimo/api/routers/followup_plans.py +147 -0
  20. apsimo/api/routers/governed_actions.py +162 -0
  21. apsimo/api/routers/host.py +14473 -0
  22. apsimo/api/routers/initiative_work.py +115 -0
  23. apsimo/api/routers/mining.py +104 -0
  24. apsimo/api/routers/observations.py +110 -0
  25. apsimo/api/routers/social_state.py +225 -0
  26. apsimo/api/routers/task_queue.py +2715 -0
  27. apsimo/api/routers/temporal_followups.py +251 -0
  28. apsimo/api/routers/transport.py +110 -0
  29. apsimo/api/routers/transport_ingress_api.py +240 -0
  30. apsimo/api/schemas/__init__.py +1 -0
  31. apsimo/api/schemas/host.py +1949 -0
  32. apsimo/autonomy/cli.py +110 -0
  33. apsimo/autonomy/condition_worker.py +437 -0
  34. apsimo/autonomy/config.py +424 -0
  35. apsimo/autonomy/loop.py +4316 -0
  36. apsimo/autonomy/registry.py +339 -0
  37. apsimo/autonomy/scheduler.py +1822 -0
  38. apsimo/autonomy/synthesis.py +449 -0
  39. apsimo/backup.py +962 -0
  40. apsimo/beliefs/__init__.py +23 -0
  41. apsimo/beliefs/contradictions.py +109 -0
  42. apsimo/beliefs/decay.py +61 -0
  43. apsimo/beliefs/engine.py +479 -0
  44. apsimo/beliefs/models.py +67 -0
  45. apsimo/beliefs/promotion.py +41 -0
  46. apsimo/beliefs/resolve.py +58 -0
  47. apsimo/beliefs/source_claims.py +690 -0
  48. apsimo/beliefs/source_projection.py +883 -0
  49. apsimo/beliefs/source_time.py +208 -0
  50. apsimo/beliefs/store.py +133 -0
  51. apsimo/briefings/aggregators.py +824 -0
  52. apsimo/briefings/composer.py +420 -0
  53. apsimo/briefings/config.py +55 -0
  54. apsimo/briefings/delivery.py +439 -0
  55. apsimo/briefings/engagement.py +97 -0
  56. apsimo/briefings/engine.py +274 -0
  57. apsimo/briefings/enhancer.py +99 -0
  58. apsimo/briefings/models.py +183 -0
  59. apsimo/briefings/scheduler.py +382 -0
  60. apsimo/briefings/store.py +435 -0
  61. apsimo/chain/__init__.py +48 -0
  62. apsimo/chain/block.py +100 -0
  63. apsimo/chain/cli.py +704 -0
  64. apsimo/chain/genesis.py +443 -0
  65. apsimo/chain/identity.py +416 -0
  66. apsimo/chain/keys.py +1025 -0
  67. apsimo/chain/local_keys.py +187 -0
  68. apsimo/chain/manager.py +290 -0
  69. apsimo/chain/node.py +163 -0
  70. apsimo/chain/plugin_transactions.py +371 -0
  71. apsimo/chain/protocol.py +220 -0
  72. apsimo/chain/state_machine.py +676 -0
  73. apsimo/chain/storage.py +503 -0
  74. apsimo/chain/transactions.py +250 -0
  75. apsimo/chain/validation.py +397 -0
  76. apsimo/channels/__init__.py +1 -0
  77. apsimo/channels/manifest.py +31 -0
  78. apsimo/channels/migrations/001_channels_schema.sql +12 -0
  79. apsimo/channels/phone_gateways.py +42 -0
  80. apsimo/channels/presence.py +188 -0
  81. apsimo/channels/router.py +235 -0
  82. apsimo/channels/store.py +231 -0
  83. apsimo/cli.py +2688 -0
  84. apsimo/cognition/__init__.py +11 -0
  85. apsimo/cognition/charter.py +398 -0
  86. apsimo/cognition/drive_governance.py +3530 -0
  87. apsimo/cognition/evidence_pipeline.py +1627 -0
  88. apsimo/cognition/external_events.py +932 -0
  89. apsimo/cognition/goal_spine.py +3488 -0
  90. apsimo/cognition/introspection.py +214 -0
  91. apsimo/cognition/prompt.py +150 -0
  92. apsimo/cognition/runtime.py +108 -0
  93. apsimo/cognition/trigger.py +154 -0
  94. apsimo/commitments/__init__.py +18 -0
  95. apsimo/commitments/local_work.py +355 -0
  96. apsimo/commitments/store.py +1052 -0
  97. apsimo/commitments/work.py +91 -0
  98. apsimo/compat.py +53 -0
  99. apsimo/compression/__init__.py +467 -0
  100. apsimo/connectors/__init__.py +21 -0
  101. apsimo/connectors/base.py +152 -0
  102. apsimo/connectors/caldav_calendar.py +125 -0
  103. apsimo/connectors/fs_documents.py +85 -0
  104. apsimo/connectors/imap_email.py +138 -0
  105. apsimo/connectors/manager.py +218 -0
  106. apsimo/connectors/webhook_pull.py +88 -0
  107. apsimo/contacts/__init__.py +33 -0
  108. apsimo/contacts/comms.py +357 -0
  109. apsimo/contacts/config.py +79 -0
  110. apsimo/contacts/exporters/__init__.py +1 -0
  111. apsimo/contacts/exporters/vcard.py +71 -0
  112. apsimo/contacts/identity_links.py +251 -0
  113. apsimo/contacts/importer.py +280 -0
  114. apsimo/contacts/importers/__init__.py +1 -0
  115. apsimo/contacts/importers/batch.py +43 -0
  116. apsimo/contacts/importers/macos_contacts.py +101 -0
  117. apsimo/contacts/migrations/001_contacts_schema.sql +141 -0
  118. apsimo/contacts/migrations/002_trust_scopes.sql +36 -0
  119. apsimo/contacts/migrations/003_open_gateway_enum.sql +32 -0
  120. apsimo/contacts/migrations/004_contact_provision_operations.sql +18 -0
  121. apsimo/contacts/migrations/005_identity_links.sql +27 -0
  122. apsimo/contacts/models.py +308 -0
  123. apsimo/contacts/scoring.py +16 -0
  124. apsimo/contacts/store.py +1623 -0
  125. apsimo/contacts/transport_ingress.py +252 -0
  126. apsimo/contacts/world_bridge.py +314 -0
  127. apsimo/contextgate/__init__.py +69 -0
  128. apsimo/contextgate/chunker.py +169 -0
  129. apsimo/contextgate/estimate.py +54 -0
  130. apsimo/contextgate/gate.py +313 -0
  131. apsimo/contextgate/retrieve.py +115 -0
  132. apsimo/delivery/__init__.py +16 -0
  133. apsimo/delivery/bridge.py +1260 -0
  134. apsimo/delivery/channels.py +526 -0
  135. apsimo/delivery/classification.py +50 -0
  136. apsimo/delivery/rate_limiter.py +268 -0
  137. apsimo/delivery/reachout_policy.py +206 -0
  138. apsimo/directed/__init__.py +22 -0
  139. apsimo/directed/audit.py +167 -0
  140. apsimo/directed/intake.py +95 -0
  141. apsimo/directed/models.py +191 -0
  142. apsimo/directed/service.py +509 -0
  143. apsimo/directives/__init__.py +25 -0
  144. apsimo/directives/evidence.py +87 -0
  145. apsimo/directives/extractor.py +188 -0
  146. apsimo/directives/guard.py +364 -0
  147. apsimo/directives/models.py +206 -0
  148. apsimo/directives/service.py +372 -0
  149. apsimo/directives/store.py +167 -0
  150. apsimo/doctor.py +2173 -0
  151. apsimo/environment.py +43 -0
  152. apsimo/events/__init__.py +33 -0
  153. apsimo/events/broadcaster.py +98 -0
  154. apsimo/events/bus.py +217 -0
  155. apsimo/events/journal.py +863 -0
  156. apsimo/events/stream.py +131 -0
  157. apsimo/events/types.py +150 -0
  158. apsimo/execution_results.py +357 -0
  159. apsimo/feedback/__init__.py +5 -0
  160. apsimo/feedback/store.py +76 -0
  161. apsimo/feeds/__init__.py +19 -0
  162. apsimo/feeds/cli.py +84 -0
  163. apsimo/feeds/engine.py +437 -0
  164. apsimo/feeds/example-feed.yaml +77 -0
  165. apsimo/feeds/hermes_cron.py +126 -0
  166. apsimo/feeds/manager.py +235 -0
  167. apsimo/feeds/spec.py +250 -0
  168. apsimo/feeds/template.py +202 -0
  169. apsimo/gate/__init__.py +18 -0
  170. apsimo/gate/audit.py +61 -0
  171. apsimo/gate/communication_policy.py +166 -0
  172. apsimo/gate/config.py +72 -0
  173. apsimo/gate/context_provenance.py +170 -0
  174. apsimo/gate/env_risk.py +226 -0
  175. apsimo/gate/guard_audit.py +353 -0
  176. apsimo/gate/layers/__init__.py +1 -0
  177. apsimo/gate/layers/base.py +15 -0
  178. apsimo/gate/layers/l1_recipient.py +66 -0
  179. apsimo/gate/layers/l2_pii.py +134 -0
  180. apsimo/gate/layers/l3_cross_context.py +50 -0
  181. apsimo/gate/layers/l4_trust_tier.py +78 -0
  182. apsimo/gate/layers/l5_injection.py +199 -0
  183. apsimo/gate/layers/l6_review.py +86 -0
  184. apsimo/gate/layers/l7_delay.py +100 -0
  185. apsimo/gate/layers/tom2_epistemic.py +185 -0
  186. apsimo/gate/models.py +64 -0
  187. apsimo/gate/pending_dispatch.py +5 -0
  188. apsimo/gate/pipeline.py +206 -0
  189. apsimo/gate/rejection.py +259 -0
  190. apsimo/gate/response_guard.py +700 -0
  191. apsimo/gate/rulesets/injection_v1.yaml +51 -0
  192. apsimo/gate/surface_policy.py +189 -0
  193. apsimo/gate/taint.py +226 -0
  194. apsimo/genesis.json +9 -0
  195. apsimo/goals/__init__.py +100 -0
  196. apsimo/goals/config.py +38 -0
  197. apsimo/goals/decomposer.py +421 -0
  198. apsimo/goals/engine.py +617 -0
  199. apsimo/goals/inference.py +354 -0
  200. apsimo/goals/models.py +302 -0
  201. apsimo/goals/priority.py +270 -0
  202. apsimo/goals/queue_bridge.py +149 -0
  203. apsimo/goals/replan.py +450 -0
  204. apsimo/goals/schema.sql +89 -0
  205. apsimo/goals/store.py +692 -0
  206. apsimo/governed_actions.py +1708 -0
  207. apsimo/harness_integration/__init__.py +45 -0
  208. apsimo/harness_integration/context.py +41 -0
  209. apsimo/harness_integration/skills.py +231 -0
  210. apsimo/identity/__init__.py +26 -0
  211. apsimo/identity/participants.py +181 -0
  212. apsimo/identity/resolver.py +329 -0
  213. apsimo/identity_bootstrap/__init__.py +5 -0
  214. apsimo/identity_bootstrap/builder.py +208 -0
  215. apsimo/identity_bootstrap/corpus.py +443 -0
  216. apsimo/identity_bootstrap/models.py +54 -0
  217. apsimo/identity_bootstrap/runner.py +353 -0
  218. apsimo/identity_bootstrap/seeders/__init__.py +25 -0
  219. apsimo/identity_bootstrap/seeders/briefings.py +109 -0
  220. apsimo/identity_bootstrap/seeders/chain.py +57 -0
  221. apsimo/identity_bootstrap/seeders/goals.py +128 -0
  222. apsimo/identity_bootstrap/seeders/memory.py +191 -0
  223. apsimo/identity_bootstrap/seeders/neo4j_cognition.py +79 -0
  224. apsimo/identity_bootstrap/seeders/relationship.py +152 -0
  225. apsimo/identity_bootstrap/seeders/sessions.py +67 -0
  226. apsimo/identity_bootstrap/seeders/skills.py +92 -0
  227. apsimo/identity_bootstrap/seeders/task_queue.py +72 -0
  228. apsimo/identity_bootstrap/seeders/world_model.py +143 -0
  229. apsimo/identity_bootstrap/self_query.py +92 -0
  230. apsimo/identity_bootstrap/self_reflection.py +155 -0
  231. apsimo/identity_bootstrap/skill.py +37 -0
  232. apsimo/identity_bootstrap/verifier.py +436 -0
  233. apsimo/initiatives/__init__.py +20 -0
  234. apsimo/initiatives/action_registry.py +454 -0
  235. apsimo/initiatives/approval_authority.py +2105 -0
  236. apsimo/initiatives/approval_policy.py +123 -0
  237. apsimo/initiatives/assignment.py +263 -0
  238. apsimo/initiatives/backup_evidence.py +100 -0
  239. apsimo/initiatives/context_freshness.py +103 -0
  240. apsimo/initiatives/models.py +318 -0
  241. apsimo/initiatives/native_work.py +270 -0
  242. apsimo/initiatives/standing_approvals.py +232 -0
  243. apsimo/initiatives/store.py +1081 -0
  244. apsimo/initiatives/temporal_followup.py +410 -0
  245. apsimo/intelligence/__init__.py +1 -0
  246. apsimo/intelligence/cognition/__init__.py +24 -0
  247. apsimo/intelligence/cognition/gap_detector.py +148 -0
  248. apsimo/intelligence/cognition/metalearner.py +547 -0
  249. apsimo/intelligence/cognition/metrics_collector.py +217 -0
  250. apsimo/intelligence/cognition/performance_index.py +299 -0
  251. apsimo/intelligence/cognition/registry.py +192 -0
  252. apsimo/intelligence/cognition/strategy_adjuster.py +222 -0
  253. apsimo/intelligence/cognition/types.py +16 -0
  254. apsimo/intelligence/components/__init__.py +66 -0
  255. apsimo/intelligence/components/anomaly_detector.py +413 -0
  256. apsimo/intelligence/components/initiative_engine.py +2643 -0
  257. apsimo/intelligence/components/preference_learner.py +521 -0
  258. apsimo/intelligence/components/research_orchestrator.py +358 -0
  259. apsimo/intelligence/components/self_directed_thinker.py +221 -0
  260. apsimo/intelligence/components/self_reflector.py +252 -0
  261. apsimo/intelligence/components/session_continuity.py +154 -0
  262. apsimo/intelligence/components/task_planner.py +320 -0
  263. apsimo/intelligence/components/tool_learner.py +217 -0
  264. apsimo/intelligence/graph/__init__.py +79 -0
  265. apsimo/intelligence/graph/client.py +2483 -0
  266. apsimo/intelligence/graph/consolidator.py +405 -0
  267. apsimo/intelligence/graph/distiller.py +312 -0
  268. apsimo/intelligence/graph/migrations.py +129 -0
  269. apsimo/intelligence/graph/queries.py +248 -0
  270. apsimo/intelligence/graph/recall.py +281 -0
  271. apsimo/intelligence/graph/reconciler.py +144 -0
  272. apsimo/intelligence/graph/schema.py +337 -0
  273. apsimo/intelligence/graph/selection.py +252 -0
  274. apsimo/intelligence/learning/__init__.py +17 -0
  275. apsimo/intelligence/learning/continuous_learner.py +245 -0
  276. apsimo/intelligence/learning/feedback_store.py +321 -0
  277. apsimo/intelligence/mind_model/__init__.py +1 -0
  278. apsimo/intelligence/mind_model/graph_baseline.py +136 -0
  279. apsimo/intelligence/mind_model/signal_collector.py +361 -0
  280. apsimo/intelligence/relationships/__init__.py +11 -0
  281. apsimo/intelligence/relationships/profiler.py +389 -0
  282. apsimo/intelligence/relationships/scorer.py +560 -0
  283. apsimo/intelligence/relationships/signal_floor.py +66 -0
  284. apsimo/intelligence/relationships/trust_tiers.py +300 -0
  285. apsimo/intelligence/synthesis/__init__.py +40 -0
  286. apsimo/intelligence/synthesis/connection_discoverer.py +379 -0
  287. apsimo/intelligence/synthesis/cross_domain_analyzer.py +287 -0
  288. apsimo/intelligence/synthesis/insight_deliverer.py +171 -0
  289. apsimo/intelligence/synthesis/insight_store.py +79 -0
  290. apsimo/intelligence/synthesis/insight_validator.py +183 -0
  291. apsimo/intelligence/synthesis/novelty_scorer.py +267 -0
  292. apsimo/intelligence/turn_middleware/__init__.py +15 -0
  293. apsimo/intelligence/turn_middleware/memory_sync.py +119 -0
  294. apsimo/mcp/__init__.py +41 -0
  295. apsimo/mcp/__main__.py +6 -0
  296. apsimo/mcp/config.py +287 -0
  297. apsimo/mcp/server.py +501 -0
  298. apsimo/migrations.py +187 -0
  299. apsimo/mining/__init__.py +27 -0
  300. apsimo/mining/corpus.py +239 -0
  301. apsimo/mining/escalations.py +289 -0
  302. apsimo/mining/models.py +169 -0
  303. apsimo/mining/store.py +210 -0
  304. apsimo/models/__init__.py +30 -0
  305. apsimo/models/memory.py +80 -0
  306. apsimo/models/mesh.py +72 -0
  307. apsimo/models/person.py +104 -0
  308. apsimo/models/signal.py +108 -0
  309. apsimo/observations/__init__.py +15 -0
  310. apsimo/observations/store.py +277 -0
  311. apsimo/patterns/__init__.py +6 -0
  312. apsimo/patterns/extract.py +187 -0
  313. apsimo/patterns/store.py +227 -0
  314. apsimo/persona/__init__.py +1 -0
  315. apsimo/persona/engine.py +611 -0
  316. apsimo/persona/manifest.py +140 -0
  317. apsimo/projects/__init__.py +28 -0
  318. apsimo/projects/engine.py +1681 -0
  319. apsimo/projects/event_outbox.py +188 -0
  320. apsimo/projects/models.py +216 -0
  321. apsimo/projects/planner.py +181 -0
  322. apsimo/projects/store.py +1446 -0
  323. apsimo/proposals/__init__.py +12 -0
  324. apsimo/proposals/engine.py +114 -0
  325. apsimo/proposals/models.py +207 -0
  326. apsimo/qualification/__init__.py +1 -0
  327. apsimo/qualification/cases.py +75 -0
  328. apsimo/qualification/cli.py +51 -0
  329. apsimo/qualification/memory_cases.py +209 -0
  330. apsimo/qualification/records.py +92 -0
  331. apsimo/qualification/report.py +87 -0
  332. apsimo/qualification/runner.py +311 -0
  333. apsimo/qualification/structured_cases.py +131 -0
  334. apsimo/reasoning/__init__.py +13 -0
  335. apsimo/reasoning/executor.py +506 -0
  336. apsimo/reasoning/loop.py +373 -0
  337. apsimo/reasoning/native_tools/__init__.py +16 -0
  338. apsimo/reasoning/native_tools/calculate.py +141 -0
  339. apsimo/reasoning/native_tools/file_ops.py +150 -0
  340. apsimo/reasoning/native_tools/web_search.py +49 -0
  341. apsimo/reasoning/tool_policy.py +182 -0
  342. apsimo/redact/__init__.py +176 -0
  343. apsimo/repos/__init__.py +5 -0
  344. apsimo/repos/mirrors.py +204 -0
  345. apsimo/research/__init__.py +41 -0
  346. apsimo/research/artifact.py +482 -0
  347. apsimo/research/gatherer.py +387 -0
  348. apsimo/research/pipeline.py +513 -0
  349. apsimo/research/search/__init__.py +7 -0
  350. apsimo/research/search/base.py +41 -0
  351. apsimo/research/search/brave.py +59 -0
  352. apsimo/research/search/cache.py +51 -0
  353. apsimo/research/search/duckduckgo.py +103 -0
  354. apsimo/research/search/orchestrator.py +119 -0
  355. apsimo/research/search/serpapi.py +59 -0
  356. apsimo/research/search/tavily.py +59 -0
  357. apsimo/research/synthesizer.py +309 -0
  358. apsimo/router/__init__.py +30 -0
  359. apsimo/router/complexity_scorer.py +148 -0
  360. apsimo/router/endpoints.py +153 -0
  361. apsimo/router/fallback.py +58 -0
  362. apsimo/router/functions.py +243 -0
  363. apsimo/router/native_policy.py +52 -0
  364. apsimo/router/router.py +762 -0
  365. apsimo/router/self_learning.py +174 -0
  366. apsimo/router/tiers.py +677 -0
  367. apsimo/sandbox/__init__.py +21 -0
  368. apsimo/sandbox/backend.py +195 -0
  369. apsimo/sandbox/manager.py +173 -0
  370. apsimo/scope_bounds.py +7 -0
  371. apsimo/secrets/__init__.py +6 -0
  372. apsimo/secrets/backends/__init__.py +8 -0
  373. apsimo/secrets/backends/base.py +42 -0
  374. apsimo/secrets/backends/env.py +110 -0
  375. apsimo/secrets/backends/keyring.py +72 -0
  376. apsimo/secrets/backends/onepassword.py +232 -0
  377. apsimo/secrets/cli.py +191 -0
  378. apsimo/secrets/manager.py +160 -0
  379. apsimo/secrets/migration.py +101 -0
  380. apsimo/secrets/types.py +98 -0
  381. apsimo/seed.py +41 -0
  382. apsimo/self_model/__init__.py +37 -0
  383. apsimo/self_model/appraisals.py +673 -0
  384. apsimo/self_model/benchmark.py +1314 -0
  385. apsimo/self_model/brief.py +40 -0
  386. apsimo/self_model/event_concerns.py +1128 -0
  387. apsimo/self_model/execution_forecasts.py +353 -0
  388. apsimo/self_model/expectations.py +1595 -0
  389. apsimo/self_model/experiments.py +1150 -0
  390. apsimo/self_model/journal.py +148 -0
  391. apsimo/self_model/judgments.py +705 -0
  392. apsimo/self_model/native_outcomes.py +55 -0
  393. apsimo/self_model/params.py +220 -0
  394. apsimo/self_model/perspective.py +246 -0
  395. apsimo/self_model/reconcile.py +183 -0
  396. apsimo/self_model/reply_forecasts.py +381 -0
  397. apsimo/self_model/runtime_forecasts.py +296 -0
  398. apsimo/self_model/runtime_models.py +67 -0
  399. apsimo/self_model/settlement.py +207 -0
  400. apsimo/self_model/situation.py +1731 -0
  401. apsimo/self_model/store.py +883 -0
  402. apsimo/self_model/supervised.py +137 -0
  403. apsimo/self_model/thinker.py +99 -0
  404. apsimo/self_model/trust.py +388 -0
  405. apsimo/self_model/workspace.py +2388 -0
  406. apsimo/server.py +4197 -0
  407. apsimo/services/__init__.py +1 -0
  408. apsimo/services/agent_bridge.py +474 -0
  409. apsimo/services/initiative_executor.py +914 -0
  410. apsimo/services/instance.py +297 -0
  411. apsimo/sessions/__init__.py +22 -0
  412. apsimo/sessions/config.py +13 -0
  413. apsimo/sessions/context_loader.py +88 -0
  414. apsimo/sessions/federation_session.py +75 -0
  415. apsimo/sessions/isolated_session.py +98 -0
  416. apsimo/sessions/reports.py +84 -0
  417. apsimo/sessions/store.py +148 -0
  418. apsimo/setup.py +2818 -0
  419. apsimo/setup_hermes.py +879 -0
  420. apsimo/setup_local_work.py +218 -0
  421. apsimo/setup_native_goals.py +134 -0
  422. apsimo/setup_native_reviews.py +115 -0
  423. apsimo/skills/__init__.py +10 -0
  424. apsimo/skills/base.py +108 -0
  425. apsimo/skills/budget.py +28 -0
  426. apsimo/skills/executor.py +493 -0
  427. apsimo/skills/executors/__init__.py +1 -0
  428. apsimo/skills/executors/behavioral_correction.py +75 -0
  429. apsimo/skills/executors/capability_gap.py +38 -0
  430. apsimo/skills/executors/data_quality.py +163 -0
  431. apsimo/skills/executors/knowledge_acquisition.py +41 -0
  432. apsimo/skills/executors/operational_hygiene.py +185 -0
  433. apsimo/skills/executors/subsystem_health.py +169 -0
  434. apsimo/skills/hermes_export.py +431 -0
  435. apsimo/skills/index.py +123 -0
  436. apsimo/skills/learning/__init__.py +21 -0
  437. apsimo/skills/learning/novelty_detector.py +206 -0
  438. apsimo/skills/learning/pattern_extractor.py +199 -0
  439. apsimo/skills/learning/triggers.py +159 -0
  440. apsimo/skills/loader.py +246 -0
  441. apsimo/skills/migrations/002_progressive_loading.sql +6 -0
  442. apsimo/skills/migrations/backfill_triggers.py +20 -0
  443. apsimo/skills/models.py +202 -0
  444. apsimo/skills/packager.py +128 -0
  445. apsimo/skills/protocols.py +70 -0
  446. apsimo/skills/registry.py +191 -0
  447. apsimo/skills/runtime.py +58 -0
  448. apsimo/skills/sandbox_runner.py +229 -0
  449. apsimo/skills/scheduler.py +129 -0
  450. apsimo/skills/schema.py +79 -0
  451. apsimo/skills/security/__init__.py +12 -0
  452. apsimo/skills/security/guards.py +53 -0
  453. apsimo/skills/security/scanner.py +223 -0
  454. apsimo/skills_memory/__init__.py +26 -0
  455. apsimo/skills_memory/distill.py +159 -0
  456. apsimo/skills_memory/models.py +85 -0
  457. apsimo/skills_memory/retrieve.py +62 -0
  458. apsimo/skills_memory/store.py +172 -0
  459. apsimo/surprise/__init__.py +6 -0
  460. apsimo/surprise/accumulation.py +57 -0
  461. apsimo/surprise/scorer.py +102 -0
  462. apsimo/surprise/store.py +203 -0
  463. apsimo/task_queue/__init__.py +69 -0
  464. apsimo/task_queue/action_receipts.py +148 -0
  465. apsimo/task_queue/approval_relay_canary.py +108 -0
  466. apsimo/task_queue/config.py +85 -0
  467. apsimo/task_queue/contract.py +361 -0
  468. apsimo/task_queue/events.py +130 -0
  469. apsimo/task_queue/governor.py +1031 -0
  470. apsimo/task_queue/handlers/__init__.py +16 -0
  471. apsimo/task_queue/handlers/base.py +37 -0
  472. apsimo/task_queue/handlers/inference.py +640 -0
  473. apsimo/task_queue/handlers/monitoring.py +116 -0
  474. apsimo/task_queue/handlers/registry.py +75 -0
  475. apsimo/task_queue/handlers/subtask_handler.py +173 -0
  476. apsimo/task_queue/handlers/system_maintenance.py +147 -0
  477. apsimo/task_queue/mesh_integration.py +111 -0
  478. apsimo/task_queue/models.py +317 -0
  479. apsimo/task_queue/queue_manager.py +8286 -0
  480. apsimo/task_queue/routing.py +287 -0
  481. apsimo/task_queue/scheduler.py +252 -0
  482. apsimo/task_queue/schema.sql +197 -0
  483. apsimo/task_queue/work_control.py +342 -0
  484. apsimo/task_queue/worker.py +993 -0
  485. apsimo/telemetry.py +145 -0
  486. apsimo/tom/__init__.py +6 -0
  487. apsimo/tom/affect.py +387 -0
  488. apsimo/tom/approvals.py +171 -0
  489. apsimo/tom/arcs.py +896 -0
  490. apsimo/tom/asymmetry.py +131 -0
  491. apsimo/tom/eligibility.py +248 -0
  492. apsimo/tom/engagement.py +214 -0
  493. apsimo/tom/exposure.py +214 -0
  494. apsimo/tom/extractor.py +306 -0
  495. apsimo/tom/fact_adapters.py +144 -0
  496. apsimo/tom/facts.py +326 -0
  497. apsimo/tom/integration.py +592 -0
  498. apsimo/tom/leveled.py +118 -0
  499. apsimo/tom/levels.py +247 -0
  500. apsimo/tom/recipient_audit.py +995 -0
  501. apsimo/tom/recipient_simulator.py +593 -0
  502. apsimo/tom/source_lineage.py +93 -0
  503. apsimo/tom/tom2.py +277 -0
  504. apsimo/tom/visibility.py +559 -0
  505. apsimo/tom/visibility_store.py +414 -0
  506. apsimo/tools/__init__.py +0 -0
  507. apsimo/tools/definitions.py +740 -0
  508. apsimo/tools/handlers.py +943 -0
  509. apsimo/toolsmith/__init__.py +26 -0
  510. apsimo/toolsmith/authority.py +166 -0
  511. apsimo/toolsmith/engine.py +559 -0
  512. apsimo/toolsmith/integrity.py +100 -0
  513. apsimo/toolsmith/miner.py +145 -0
  514. apsimo/toolsmith/policy.py +110 -0
  515. apsimo/toolsmith/registry.py +635 -0
  516. apsimo/turns/__init__.py +17 -0
  517. apsimo/turns/audio.py +134 -0
  518. apsimo/turns/documents.py +235 -0
  519. apsimo/turns/executions.py +486 -0
  520. apsimo/turns/hermes_history.py +245 -0
  521. apsimo/turns/hermes_kanban.py +268 -0
  522. apsimo/turns/hermes_work.py +96 -0
  523. apsimo/turns/idempotency.py +752 -0
  524. apsimo/turns/local_work.py +115 -0
  525. apsimo/turns/media.py +581 -0
  526. apsimo/turns/reported_workers.py +196 -0
  527. apsimo/turns/source_annotations.py +283 -0
  528. apsimo/turns/source_attribution.py +154 -0
  529. apsimo/turns/source_read.py +351 -0
  530. apsimo/turns/source_vectors.py +263 -0
  531. apsimo/turns/video.py +210 -0
  532. apsimo/util/autonomy_preset.py +220 -0
  533. apsimo/util/instance.py +92 -0
  534. apsimo/util/model_output.py +25 -0
  535. apsimo/util/quiet_hours.py +27 -0
  536. apsimo/util/session_safety.py +37 -0
  537. apsimo/util/temporal.py +343 -0
  538. apsimo/vector/__init__.py +75 -0
  539. apsimo/vector/backfill.py +171 -0
  540. apsimo/vector/caption.py +114 -0
  541. apsimo/vector/collections.py +51 -0
  542. apsimo/vector/config.py +102 -0
  543. apsimo/vector/embedder.py +670 -0
  544. apsimo/vector/image_preprocess.py +406 -0
  545. apsimo/vector/image_store.py +296 -0
  546. apsimo/vector/indexes.py +162 -0
  547. apsimo/vector/migrate.py +334 -0
  548. apsimo/vector/multimodal_provider.py +417 -0
  549. apsimo/vector/multimodal_types.py +87 -0
  550. apsimo/vector/openai_provider.py +119 -0
  551. apsimo/vector/query.py +49 -0
  552. apsimo/vector/reranker.py +565 -0
  553. apsimo/vector/safety_image.py +159 -0
  554. apsimo/vector/scanner.py +197 -0
  555. apsimo/vector/setup.py +289 -0
  556. apsimo/vector/store.py +533 -0
  557. apsimo/vector/tiers.py +263 -0
  558. apsimo/work_orders.py +925 -0
  559. apsimo/workers/__init__.py +21 -0
  560. apsimo/workers/agent_bridge.py +640 -0
  561. apsimo/workers/colony_worker.py +382 -0
  562. apsimo/workers/queue_worker.py +441 -0
  563. apsimo/workers/skills_sync.py +152 -0
  564. apsimo/world_model/__init__.py +71 -0
  565. apsimo/world_model/causal_maintenance.py +131 -0
  566. apsimo/world_model/causal_policy.py +43 -0
  567. apsimo/world_model/causal_query.py +125 -0
  568. apsimo/world_model/confidence.py +54 -0
  569. apsimo/world_model/config.py +64 -0
  570. apsimo/world_model/constants.py +97 -0
  571. apsimo/world_model/entities.py +145 -0
  572. apsimo/world_model/expectation_resolvers.py +177 -0
  573. apsimo/world_model/extraction/__init__.py +7 -0
  574. apsimo/world_model/extraction/base.py +62 -0
  575. apsimo/world_model/extraction/conversation_extractor.py +262 -0
  576. apsimo/world_model/extraction/detector.py +74 -0
  577. apsimo/world_model/extraction/document_extractor.py +78 -0
  578. apsimo/world_model/extraction/formats/__init__.py +24 -0
  579. apsimo/world_model/extraction/formats/csv_fmt.py +68 -0
  580. apsimo/world_model/extraction/formats/html_fmt.py +72 -0
  581. apsimo/world_model/extraction/formats/json_fmt.py +68 -0
  582. apsimo/world_model/extraction/formats/pdf.py +43 -0
  583. apsimo/world_model/extraction/formats/text.py +27 -0
  584. apsimo/world_model/extraction/llm_extractor.py +164 -0
  585. apsimo/world_model/extraction/pipeline.py +73 -0
  586. apsimo/world_model/integrations/__init__.py +5 -0
  587. apsimo/world_model/integrations/mind_model_bridge.py +115 -0
  588. apsimo/world_model/integrations/social_intel_bridge.py +120 -0
  589. apsimo/world_model/jobs/__init__.py +4 -0
  590. apsimo/world_model/jobs/extraction_job.py +168 -0
  591. apsimo/world_model/llm_extract.py +572 -0
  592. apsimo/world_model/neo4j/__init__.py +5 -0
  593. apsimo/world_model/neo4j/backend.py +654 -0
  594. apsimo/world_model/observations.py +155 -0
  595. apsimo/world_model/populator.py +307 -0
  596. apsimo/world_model/postgres/__init__.py +1 -0
  597. apsimo/world_model/postgres/backend.py +683 -0
  598. apsimo/world_model/relationships.py +25 -0
  599. apsimo/world_model/resolution/__init__.py +13 -0
  600. apsimo/world_model/resolution/entity_resolver.py +232 -0
  601. apsimo/world_model/resolution/merge_audit.py +16 -0
  602. apsimo/world_model/resolution/merge_workflow.py +117 -0
  603. apsimo/world_model/source_reports.py +121 -0
  604. apsimo/world_model/sqlite/__init__.py +4 -0
  605. apsimo/world_model/sqlite/backend.py +855 -0
  606. apsimo/world_model/sqlite/schema.sql +132 -0
  607. apsimo/world_model/store.py +545 -0
  608. apsimo-1.3.0.dist-info/METADATA +78 -0
  609. apsimo-1.3.0.dist-info/RECORD +614 -0
  610. apsimo-1.3.0.dist-info/WHEEL +5 -0
  611. apsimo-1.3.0.dist-info/entry_points.txt +11 -0
  612. apsimo-1.3.0.dist-info/licenses/LICENSE +21 -0
  613. apsimo-1.3.0.dist-info/top_level.txt +2 -0
  614. colony_sidecar/__init__.py +4 -0
@@ -0,0 +1,503 @@
1
+ """SQLite-backed persistent storage for ColonyChain.
2
+
3
+ Stores blocks, transactions, mempool, checkpoints, and chain metadata.
4
+ Supports full chain replay and state verification.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import logging
11
+ import sqlite3
12
+ from contextlib import contextmanager
13
+ from dataclasses import asdict
14
+ from datetime import datetime, timezone
15
+ from pathlib import Path
16
+ from typing import Any, Generator
17
+
18
+ from .block import Block
19
+ from .transactions import (
20
+ ChainState,
21
+ ColonyRecord,
22
+ KeyHistoryEntry,
23
+ ProtocolConfig,
24
+ ProtocolUpgradeRecord,
25
+ SentinelRecord,
26
+ Transaction,
27
+ TrustEdge,
28
+ TxType,
29
+ UntrustEvent,
30
+ )
31
+
32
+ logger = logging.getLogger(__name__)
33
+
34
+ _SCHEMA = """
35
+ PRAGMA journal_mode=WAL;
36
+ PRAGMA foreign_keys=ON;
37
+
38
+ CREATE TABLE IF NOT EXISTS chain_blocks (
39
+ block_index INTEGER PRIMARY KEY,
40
+ block_hash TEXT NOT NULL UNIQUE,
41
+ previous_hash TEXT NOT NULL,
42
+ timestamp TEXT NOT NULL,
43
+ merkle_root TEXT NOT NULL,
44
+ producer_id TEXT NOT NULL,
45
+ signature TEXT NOT NULL,
46
+ raw_json TEXT NOT NULL,
47
+ committed_at TEXT NOT NULL
48
+ );
49
+
50
+ CREATE TABLE IF NOT EXISTS chain_transactions (
51
+ tx_id TEXT PRIMARY KEY,
52
+ block_index INTEGER NOT NULL REFERENCES chain_blocks(block_index),
53
+ tx_type TEXT NOT NULL,
54
+ from_colony_id TEXT NOT NULL,
55
+ timestamp TEXT NOT NULL,
56
+ nonce INTEGER NOT NULL,
57
+ payload_json TEXT NOT NULL,
58
+ signature TEXT NOT NULL,
59
+ UNIQUE(from_colony_id, nonce)
60
+ );
61
+
62
+ CREATE TABLE IF NOT EXISTS chain_checkpoints (
63
+ height INTEGER PRIMARY KEY,
64
+ state_json TEXT NOT NULL,
65
+ created_at TEXT NOT NULL
66
+ );
67
+
68
+ CREATE TABLE IF NOT EXISTS chain_meta (
69
+ key TEXT PRIMARY KEY,
70
+ value TEXT NOT NULL
71
+ );
72
+
73
+ CREATE TABLE IF NOT EXISTS chain_mempool (
74
+ tx_id TEXT PRIMARY KEY,
75
+ tx_type TEXT NOT NULL,
76
+ from_colony_id TEXT NOT NULL,
77
+ received_at TEXT NOT NULL,
78
+ priority INTEGER NOT NULL DEFAULT 0,
79
+ payload_json TEXT NOT NULL,
80
+ signature TEXT NOT NULL,
81
+ raw_json TEXT NOT NULL,
82
+ expires_at TEXT
83
+ );
84
+
85
+ CREATE INDEX IF NOT EXISTS idx_tx_colony ON chain_transactions(from_colony_id);
86
+ CREATE INDEX IF NOT EXISTS idx_tx_type ON chain_transactions(tx_type);
87
+ CREATE INDEX IF NOT EXISTS idx_block_ts ON chain_blocks(timestamp);
88
+ CREATE INDEX IF NOT EXISTS idx_tx_block ON chain_transactions(block_index);
89
+ CREATE INDEX IF NOT EXISTS idx_mempool_ord ON chain_mempool(priority DESC, received_at ASC);
90
+ CREATE INDEX IF NOT EXISTS idx_mempool_exp ON chain_mempool(expires_at) WHERE expires_at IS NOT NULL;
91
+ CREATE INDEX IF NOT EXISTS idx_block_prod ON chain_blocks(producer_id);
92
+ """
93
+
94
+
95
+ class ChainStore:
96
+ """SQLite-backed persistent chain storage."""
97
+
98
+ def __init__(self, db_path: Path | str) -> None:
99
+ self.db_path = Path(db_path)
100
+ self.db_path.parent.mkdir(parents=True, exist_ok=True)
101
+ self._init_db()
102
+
103
+ def _get_conn(self) -> sqlite3.Connection:
104
+ conn = sqlite3.connect(str(self.db_path), timeout=30.0)
105
+ conn.row_factory = sqlite3.Row
106
+ conn.execute("PRAGMA journal_mode=WAL")
107
+ conn.execute("PRAGMA synchronous=FULL") # durability > speed for chain data (SEC-14-L-04)
108
+ conn.execute("PRAGMA busy_timeout=10000")
109
+ conn.execute("PRAGMA cache_size=-8000")
110
+ return conn
111
+
112
+ @contextmanager
113
+ def _tx(self) -> Generator[sqlite3.Connection, None, None]:
114
+ conn = self._get_conn()
115
+ try:
116
+ yield conn
117
+ conn.commit()
118
+ except Exception:
119
+ conn.rollback()
120
+ raise
121
+ finally:
122
+ conn.close()
123
+
124
+ def _init_db(self) -> None:
125
+ with self._tx() as conn:
126
+ conn.executescript(_SCHEMA)
127
+
128
+ # ── Block operations ────────────────────────────────────────────────────
129
+
130
+ def append_block(self, block: Block) -> None:
131
+ """Append a committed block. Raises if hash chain is broken."""
132
+ latest = self.get_latest_block()
133
+ if latest is not None:
134
+ if block.previous_hash != latest.block_hash:
135
+ raise ValueError(
136
+ f"Hash chain broken: block {block.index} previous_hash "
137
+ f"{block.previous_hash!r} != latest hash {latest.block_hash!r}"
138
+ )
139
+ if block.index != latest.index + 1:
140
+ raise ValueError(
141
+ f"Block index gap: expected {latest.index + 1}, got {block.index}"
142
+ )
143
+ else:
144
+ if block.index != 0:
145
+ raise ValueError(f"First block must have index 0, got {block.index}")
146
+
147
+ raw_json = json.dumps(block.to_dict(), sort_keys=True)
148
+ committed_at = datetime.now(timezone.utc).isoformat()
149
+ with self._tx() as conn:
150
+ conn.execute(
151
+ """INSERT INTO chain_blocks
152
+ (block_index, block_hash, previous_hash, timestamp,
153
+ merkle_root, producer_id, signature, raw_json, committed_at)
154
+ VALUES (?,?,?,?,?,?,?,?,?)""",
155
+ (
156
+ block.index,
157
+ block.block_hash,
158
+ block.previous_hash,
159
+ block.timestamp,
160
+ block.merkle_root,
161
+ block.producer_id,
162
+ block.signature,
163
+ raw_json,
164
+ committed_at,
165
+ ),
166
+ )
167
+ for tx in block.transactions:
168
+ conn.execute(
169
+ """INSERT OR IGNORE INTO chain_transactions
170
+ (tx_id, block_index, tx_type, from_colony_id, timestamp,
171
+ nonce, payload_json, signature)
172
+ VALUES (?,?,?,?,?,?,?,?)""",
173
+ (
174
+ tx.tx_id,
175
+ block.index,
176
+ tx.type.value if isinstance(tx.type, TxType) else tx.type,
177
+ tx.from_colony_id,
178
+ tx.timestamp,
179
+ tx.nonce,
180
+ json.dumps(tx.payload),
181
+ tx.signature,
182
+ ),
183
+ )
184
+ # Remove from mempool
185
+ for tx in block.transactions:
186
+ conn.execute(
187
+ "DELETE FROM chain_mempool WHERE tx_id = ?", (tx.tx_id,)
188
+ )
189
+
190
+ def get_block(self, index: int) -> Block | None:
191
+ with self._get_conn() as conn:
192
+ row = conn.execute(
193
+ "SELECT raw_json FROM chain_blocks WHERE block_index = ?", (index,)
194
+ ).fetchone()
195
+ if row is None:
196
+ return None
197
+ return Block.from_dict(json.loads(row["raw_json"]))
198
+
199
+ def get_block_by_hash(self, block_hash: str) -> Block | None:
200
+ with self._get_conn() as conn:
201
+ row = conn.execute(
202
+ "SELECT raw_json FROM chain_blocks WHERE block_hash = ?", (block_hash,)
203
+ ).fetchone()
204
+ if row is None:
205
+ return None
206
+ return Block.from_dict(json.loads(row["raw_json"]))
207
+
208
+ def get_latest_block(self) -> Block | None:
209
+ with self._get_conn() as conn:
210
+ row = conn.execute(
211
+ "SELECT raw_json FROM chain_blocks ORDER BY block_index DESC LIMIT 1"
212
+ ).fetchone()
213
+ if row is None:
214
+ return None
215
+ return Block.from_dict(json.loads(row["raw_json"]))
216
+
217
+ def get_block_range(self, from_index: int, to_index: int) -> list[Block]:
218
+ with self._get_conn() as conn:
219
+ rows = conn.execute(
220
+ "SELECT raw_json FROM chain_blocks "
221
+ "WHERE block_index >= ? AND block_index <= ? "
222
+ "ORDER BY block_index ASC",
223
+ (from_index, to_index),
224
+ ).fetchall()
225
+ return [Block.from_dict(json.loads(r["raw_json"])) for r in rows]
226
+
227
+ def get_height(self) -> int:
228
+ with self._get_conn() as conn:
229
+ row = conn.execute(
230
+ "SELECT MAX(block_index) as h FROM chain_blocks"
231
+ ).fetchone()
232
+ if row is None or row["h"] is None:
233
+ return -1
234
+ return row["h"]
235
+
236
+ # ── Mempool operations ──────────────────────────────────────────────────
237
+
238
+ def add_to_mempool(self, tx: Transaction) -> None:
239
+ """Add a validated transaction to the mempool."""
240
+ received_at = datetime.now(timezone.utc).isoformat()
241
+ raw_json = json.dumps(tx.to_dict())
242
+ with self._tx() as conn:
243
+ conn.execute(
244
+ """INSERT OR IGNORE INTO chain_mempool
245
+ (tx_id, tx_type, from_colony_id, received_at, priority,
246
+ payload_json, signature, raw_json)
247
+ VALUES (?,?,?,?,?,?,?,?)""",
248
+ (
249
+ tx.tx_id,
250
+ tx.type.value if isinstance(tx.type, TxType) else tx.type,
251
+ tx.from_colony_id,
252
+ received_at,
253
+ 0,
254
+ json.dumps(tx.payload),
255
+ tx.signature,
256
+ raw_json,
257
+ ),
258
+ )
259
+
260
+ def get_mempool(self, limit: int = 500) -> list[Transaction]:
261
+ with self._get_conn() as conn:
262
+ rows = conn.execute(
263
+ "SELECT raw_json FROM chain_mempool "
264
+ "ORDER BY priority DESC, received_at ASC LIMIT ?",
265
+ (limit,),
266
+ ).fetchall()
267
+ return [Transaction.from_dict(json.loads(r["raw_json"])) for r in rows]
268
+
269
+ def remove_from_mempool(self, tx_ids: list[str]) -> None:
270
+ if not tx_ids:
271
+ return
272
+ with self._tx() as conn:
273
+ placeholders = ",".join("?" for _ in tx_ids)
274
+ conn.execute(
275
+ f"DELETE FROM chain_mempool WHERE tx_id IN ({placeholders})", tx_ids
276
+ )
277
+
278
+ def mempool_size(self) -> int:
279
+ with self._get_conn() as conn:
280
+ row = conn.execute("SELECT COUNT(*) as n FROM chain_mempool").fetchone()
281
+ return row["n"] if row else 0
282
+
283
+ # ── Nonce tracking ──────────────────────────────────────────────────────
284
+
285
+ def get_nonce(self, colony_id: str) -> int:
286
+ """Return the highest accepted nonce for colony_id (0 if none)."""
287
+ with self._get_conn() as conn:
288
+ row = conn.execute(
289
+ "SELECT MAX(nonce) as n FROM chain_transactions WHERE from_colony_id = ?",
290
+ (colony_id,),
291
+ ).fetchone()
292
+ if row is None or row["n"] is None:
293
+ return 0
294
+ return row["n"]
295
+
296
+ # ── Checkpoint operations ───────────────────────────────────────────────
297
+
298
+ def save_checkpoint(self, state: ChainState, height: int) -> None:
299
+ state_json = _serialize_chain_state(state)
300
+ created_at = datetime.now(timezone.utc).isoformat()
301
+ with self._tx() as conn:
302
+ conn.execute(
303
+ "INSERT OR REPLACE INTO chain_checkpoints (height, state_json, created_at) "
304
+ "VALUES (?,?,?)",
305
+ (height, state_json, created_at),
306
+ )
307
+
308
+ def get_latest_checkpoint(
309
+ self, at_or_before: int
310
+ ) -> tuple[ChainState, int] | None:
311
+ with self._get_conn() as conn:
312
+ row = conn.execute(
313
+ "SELECT height, state_json FROM chain_checkpoints "
314
+ "WHERE height <= ? ORDER BY height DESC LIMIT 1",
315
+ (at_or_before,),
316
+ ).fetchone()
317
+ if row is None:
318
+ return None
319
+ state = _deserialize_chain_state(row["state_json"])
320
+ return state, row["height"]
321
+
322
+ # ── Query helpers ───────────────────────────────────────────────────────
323
+
324
+ def get_transactions_for_colony(self, colony_id: str) -> list[Transaction]:
325
+ with self._get_conn() as conn:
326
+ rows = conn.execute(
327
+ "SELECT tx_id, tx_type, from_colony_id, timestamp, nonce, "
328
+ "payload_json, signature FROM chain_transactions "
329
+ "WHERE from_colony_id = ? ORDER BY nonce ASC",
330
+ (colony_id,),
331
+ ).fetchall()
332
+ result = []
333
+ for r in rows:
334
+ result.append(
335
+ Transaction(
336
+ tx_id=r["tx_id"],
337
+ type=TxType(r["tx_type"]),
338
+ from_colony_id=r["from_colony_id"],
339
+ timestamp=r["timestamp"],
340
+ nonce=r["nonce"],
341
+ payload=json.loads(r["payload_json"]),
342
+ signature=r["signature"],
343
+ )
344
+ )
345
+ return result
346
+
347
+ # ── Metadata ────────────────────────────────────────────────────────────
348
+
349
+ def set_meta(self, key: str, value: str) -> None:
350
+ with self._tx() as conn:
351
+ conn.execute(
352
+ "INSERT OR REPLACE INTO chain_meta (key, value) VALUES (?,?)",
353
+ (key, value),
354
+ )
355
+
356
+ def get_meta(self, key: str) -> str | None:
357
+ with self._get_conn() as conn:
358
+ row = conn.execute(
359
+ "SELECT value FROM chain_meta WHERE key = ?", (key,)
360
+ ).fetchone()
361
+ return row["value"] if row else None
362
+
363
+
364
+ # ---------------------------------------------------------------------------
365
+ # ChainState serialization helpers
366
+ # ---------------------------------------------------------------------------
367
+
368
+ def _serialize_chain_state(state: ChainState) -> str:
369
+ """Serialize ChainState to JSON string."""
370
+
371
+ def _ke(e: KeyHistoryEntry) -> dict:
372
+ return {
373
+ "public_key_hex": e.public_key_hex,
374
+ "active_from_height": e.active_from_height,
375
+ "rotated_at_height": e.rotated_at_height,
376
+ "revoked_at_height": e.revoked_at_height,
377
+ "revocation_tx": e.revocation_tx,
378
+ }
379
+
380
+ def _te(e: TrustEdge) -> dict:
381
+ return {
382
+ "from_colony_id": e.from_colony_id,
383
+ "to_colony_id": e.to_colony_id,
384
+ "trust_level": e.trust_level,
385
+ "attested_at_height": e.attested_at_height,
386
+ "attested_at_tx": e.attested_at_tx,
387
+ "valid_until": e.valid_until,
388
+ }
389
+
390
+ def _ue(e: UntrustEvent) -> dict:
391
+ return {
392
+ "from_colony_id": e.from_colony_id,
393
+ "target_colony_id": e.target_colony_id,
394
+ "at_height": e.at_height,
395
+ "tx_id": e.tx_id,
396
+ "report_abuse": e.report_abuse,
397
+ "timestamp": e.timestamp,
398
+ }
399
+
400
+ def _sr(r: SentinelRecord) -> dict:
401
+ return {
402
+ "sentinel_id": r.sentinel_id,
403
+ "colony_id": r.colony_id,
404
+ "host": r.host,
405
+ "port": r.port,
406
+ "public_key_hex": r.public_key_hex,
407
+ "registered_at_height": r.registered_at_height,
408
+ "status": r.status,
409
+ "uptime_percent": r.uptime_percent,
410
+ }
411
+
412
+ def _cr(r: ColonyRecord) -> dict:
413
+ return {
414
+ "colony_id": r.colony_id,
415
+ "name": r.name,
416
+ "active_public_key_hex": r.active_public_key_hex,
417
+ "endpoint": r.endpoint,
418
+ "description": r.description,
419
+ "capabilities": r.capabilities,
420
+ "protocol_version": r.protocol_version,
421
+ "registered_at_height": r.registered_at_height,
422
+ "registered_at_tx": r.registered_at_tx,
423
+ "is_genesis_admin": r.is_genesis_admin,
424
+ "status": r.status,
425
+ "metadata": r.metadata,
426
+ }
427
+
428
+ data: dict[str, Any] = {
429
+ "height": state.height,
430
+ "last_block_hash": state.last_block_hash,
431
+ "colony_registry": {k: _cr(v) for k, v in state.colony_registry.items()},
432
+ "name_registry": state.name_registry,
433
+ "key_history": {k: [_ke(e) for e in v] for k, v in state.key_history.items()},
434
+ "trust_graph": {
435
+ json.dumps(list(k)): _te(v) for k, v in state.trust_graph.items()
436
+ },
437
+ "untrust_counters": {
438
+ k: [_ue(e) for e in v] for k, v in state.untrust_counters.items()
439
+ },
440
+ "sentinel_roster": {k: _sr(v) for k, v in state.sentinel_roster.items()},
441
+ "suspended_colonies": list(state.suspended_colonies),
442
+ "protocol_config": {
443
+ "block_interval_secs": state.protocol_config.block_interval_secs,
444
+ "untrust_threshold": state.protocol_config.untrust_threshold,
445
+ "untrust_window_days": state.protocol_config.untrust_window_days,
446
+ "uptime_requirement_percent": state.protocol_config.uptime_requirement_percent,
447
+ "min_sentinels": state.protocol_config.min_sentinels,
448
+ "min_protocol_version": state.protocol_config.min_protocol_version,
449
+ },
450
+ "upgrade_history": [
451
+ {
452
+ "upgrade_id": u.upgrade_id,
453
+ "title": u.title,
454
+ "proposed_at_height": u.proposed_at_height,
455
+ "activation_height": u.activation_height,
456
+ "ratified": u.ratified,
457
+ "changes": u.changes,
458
+ }
459
+ for u in state.upgrade_history
460
+ ],
461
+ "genesis_admin_id": state.genesis_admin_id,
462
+ "network_id": state.network_id,
463
+ }
464
+ return json.dumps(data, sort_keys=True)
465
+
466
+
467
+ def _deserialize_chain_state(state_json: str) -> ChainState:
468
+ """Deserialize ChainState from JSON string."""
469
+ data = json.loads(state_json)
470
+ state = ChainState()
471
+ state.height = data["height"]
472
+ state.last_block_hash = data["last_block_hash"]
473
+
474
+ for k, v in data["colony_registry"].items():
475
+ state.colony_registry[k] = ColonyRecord(**v)
476
+
477
+ state.name_registry = data["name_registry"]
478
+
479
+ for k, entries in data["key_history"].items():
480
+ state.key_history[k] = [KeyHistoryEntry(**e) for e in entries]
481
+
482
+ for k_str, v in data["trust_graph"].items():
483
+ k_list = json.loads(k_str)
484
+ key = (k_list[0], k_list[1])
485
+ state.trust_graph[key] = TrustEdge(**v)
486
+
487
+ for k, events in data["untrust_counters"].items():
488
+ state.untrust_counters[k] = [UntrustEvent(**e) for e in events]
489
+
490
+ for k, v in data["sentinel_roster"].items():
491
+ state.sentinel_roster[k] = SentinelRecord(**v)
492
+
493
+ state.suspended_colonies = set(data["suspended_colonies"])
494
+
495
+ pc = data["protocol_config"]
496
+ state.protocol_config = ProtocolConfig(**pc)
497
+
498
+ state.upgrade_history = [
499
+ ProtocolUpgradeRecord(**u) for u in data.get("upgrade_history", [])
500
+ ]
501
+ state.genesis_admin_id = data.get("genesis_admin_id", "")
502
+ state.network_id = data.get("network_id", "")
503
+ return state