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,371 @@
1
+ """Plugin security attestation transaction types and chain state for ColonyChain.
2
+
3
+ Defines the plugin attestation transaction set:
4
+ - PluginPublishPayload
5
+ - PluginAttestationPayload
6
+ - PluginFlagPayload
7
+ - PluginChainRecord (on-chain registry entry)
8
+
9
+ These extend the existing ColonyChain transaction set.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import hashlib
15
+ import json
16
+ from dataclasses import dataclass, field
17
+ from datetime import datetime, timezone
18
+ from enum import Enum
19
+ from typing import Any, Dict, List, Optional
20
+ from uuid import uuid4
21
+
22
+
23
+ # ---------------------------------------------------------------------------
24
+ # Enums
25
+ # ---------------------------------------------------------------------------
26
+
27
+ class ScanResult(str, Enum):
28
+ SAFE = "SAFE"
29
+ FLAGGED = "FLAGGED"
30
+ ERROR = "ERROR"
31
+ SKIPPED = "SKIPPED"
32
+
33
+
34
+ class FindingSeverity(str, Enum):
35
+ INFO = "info"
36
+ LOW = "low"
37
+ MEDIUM = "medium"
38
+ HIGH = "high"
39
+ CRITICAL = "critical"
40
+
41
+
42
+ class FindingCategory(str, Enum):
43
+ DANGEROUS_IMPORT = "dangerous_import"
44
+ EXEC_DETECTED = "exec_detected"
45
+ NETWORK_ACCESS = "network_access"
46
+ FS_WRITE = "fs_write"
47
+ SUBPROCESS = "subprocess"
48
+ OBFUSCATION = "obfuscation"
49
+ KNOWN_CVE = "known_cve"
50
+ BEHAVIOR_ANOMALY = "behavior_anomaly"
51
+
52
+
53
+ class PluginChainStatus(str, Enum):
54
+ PENDING_SCAN = "PENDING_SCAN"
55
+ SAFE = "SAFE"
56
+ FLAGGED = "FLAGGED"
57
+ QUARANTINED = "QUARANTINED"
58
+ DEPRECATED = "DEPRECATED"
59
+
60
+
61
+ # ---------------------------------------------------------------------------
62
+ # Supporting data classes
63
+ # ---------------------------------------------------------------------------
64
+
65
+ @dataclass
66
+ class ScanFinding:
67
+ """A single finding from a scan stage."""
68
+ finding_id: str = field(default_factory=lambda: str(uuid4()))
69
+ stage: str = "" # static_ast | dependency_check | dynamic_analysis
70
+ severity: FindingSeverity = FindingSeverity.INFO
71
+ category: FindingCategory = FindingCategory.DANGEROUS_IMPORT
72
+ description: str = ""
73
+ location: str = ""
74
+ evidence_snippet: str = ""
75
+ cve_id: Optional[str] = None
76
+
77
+ def to_dict(self) -> Dict[str, Any]:
78
+ return {
79
+ "finding_id": self.finding_id,
80
+ "stage": self.stage,
81
+ "severity": self.severity.value,
82
+ "category": self.category.value,
83
+ "description": self.description,
84
+ "location": self.location,
85
+ "evidence_snippet": self.evidence_snippet,
86
+ "cve_id": self.cve_id,
87
+ }
88
+
89
+
90
+ @dataclass
91
+ class PluginPermissionsPayload:
92
+ """Permissions block embedded in plugin_publish payload."""
93
+ allowed_domains: List[str] = field(default_factory=list)
94
+ allowed_read_paths: List[str] = field(default_factory=list)
95
+ allowed_write_paths: List[str] = field(default_factory=list)
96
+ allowed_env_vars: List[str] = field(default_factory=list)
97
+ max_memory_mb: int = 256
98
+ max_duration_secs: int = 30
99
+
100
+ def to_dict(self) -> Dict[str, Any]:
101
+ return {
102
+ "allowed_domains": self.allowed_domains,
103
+ "allowed_read_paths": self.allowed_read_paths,
104
+ "allowed_write_paths": self.allowed_write_paths,
105
+ "allowed_env_vars": self.allowed_env_vars,
106
+ "max_memory_mb": self.max_memory_mb,
107
+ "max_duration_secs": self.max_duration_secs,
108
+ }
109
+
110
+ @classmethod
111
+ def from_dict(cls, d: Dict[str, Any]) -> "PluginPermissionsPayload":
112
+ return cls(
113
+ allowed_domains=d.get("allowed_domains", []),
114
+ allowed_read_paths=d.get("allowed_read_paths", []),
115
+ allowed_write_paths=d.get("allowed_write_paths", []),
116
+ allowed_env_vars=d.get("allowed_env_vars", []),
117
+ max_memory_mb=d.get("max_memory_mb", 256),
118
+ max_duration_secs=d.get("max_duration_secs", 30),
119
+ )
120
+
121
+
122
+ # ---------------------------------------------------------------------------
123
+ # Transaction payload builders
124
+ # ---------------------------------------------------------------------------
125
+
126
+ @dataclass
127
+ class PluginPublishPayload:
128
+ """Payload for a plugin_publish chain transaction.
129
+
130
+ The publisher_signature field signs the canonical_signing_dict() result.
131
+ """
132
+ name: str
133
+ version: str
134
+ plugin_hash: str # SHA-256 hex of archive
135
+ publisher_colony_id: str
136
+ description: str
137
+ capabilities: List[str]
138
+ permissions: PluginPermissionsPayload
139
+ dependencies: List[str]
140
+ publisher_signature: str = "" # filled by caller before submission
141
+ min_colony_version: str = "0.1.0"
142
+ tags: List[str] = field(default_factory=list)
143
+ source_url: Optional[str] = None
144
+ metadata: Dict[str, Any] = field(default_factory=dict)
145
+
146
+ def canonical_signing_dict(self) -> Dict[str, Any]:
147
+ """Returns the dict that publisher_signature must cover.
148
+
149
+ Sorted keys, no whitespace when serialised to JSON.
150
+ """
151
+ return {
152
+ "capabilities": sorted(self.capabilities),
153
+ "dependencies": sorted(self.dependencies),
154
+ "name": self.name,
155
+ "plugin_hash": self.plugin_hash,
156
+ "publisher_colony_id": self.publisher_colony_id,
157
+ "version": self.version,
158
+ }
159
+
160
+ def canonical_signing_bytes(self) -> bytes:
161
+ return json.dumps(
162
+ self.canonical_signing_dict(), sort_keys=True, separators=(",", ":")
163
+ ).encode()
164
+
165
+ def to_dict(self) -> Dict[str, Any]:
166
+ return {
167
+ "name": self.name,
168
+ "version": self.version,
169
+ "plugin_hash": self.plugin_hash,
170
+ "publisher_colony_id": self.publisher_colony_id,
171
+ "publisher_signature": self.publisher_signature,
172
+ "description": self.description,
173
+ "capabilities": self.capabilities,
174
+ "permissions": self.permissions.to_dict(),
175
+ "dependencies": self.dependencies,
176
+ "min_colony_version": self.min_colony_version,
177
+ "tags": self.tags,
178
+ "source_url": self.source_url,
179
+ "metadata": self.metadata,
180
+ }
181
+
182
+ @classmethod
183
+ def from_dict(cls, d: Dict[str, Any]) -> "PluginPublishPayload":
184
+ perms_raw = d.get("permissions", {})
185
+ return cls(
186
+ name=d["name"],
187
+ version=d["version"],
188
+ plugin_hash=d["plugin_hash"],
189
+ publisher_colony_id=d["publisher_colony_id"],
190
+ description=d.get("description", ""),
191
+ capabilities=d.get("capabilities", []),
192
+ permissions=PluginPermissionsPayload.from_dict(perms_raw),
193
+ dependencies=d.get("dependencies", []),
194
+ publisher_signature=d.get("publisher_signature", ""),
195
+ min_colony_version=d.get("min_colony_version", "0.1.0"),
196
+ tags=d.get("tags", []),
197
+ source_url=d.get("source_url"),
198
+ metadata=d.get("metadata", {}),
199
+ )
200
+
201
+
202
+ @dataclass
203
+ class PluginAttestationPayload:
204
+ """Payload for a plugin_attestation chain transaction."""
205
+ scanner_colony_id: str
206
+ plugin_hash: str
207
+ plugin_name: str
208
+ plugin_version: str
209
+ scan_result: ScanResult
210
+ findings: List[ScanFinding]
211
+ scanner_version: str
212
+ scan_policy_version: str
213
+ scanned_at: datetime
214
+ container_image: str
215
+ stages_completed: List[str]
216
+ scanner_signature: str = "" # filled by caller before submission
217
+
218
+ @property
219
+ def findings_hash(self) -> str:
220
+ """SHA-256 of canonical JSON of findings list."""
221
+ findings_json = json.dumps(
222
+ [f.to_dict() for f in self.findings],
223
+ sort_keys=True,
224
+ separators=(",", ":"),
225
+ )
226
+ return hashlib.sha256(findings_json.encode()).hexdigest()
227
+
228
+ def canonical_signing_dict(self) -> Dict[str, Any]:
229
+ return {
230
+ "findings_hash": self.findings_hash,
231
+ "plugin_hash": self.plugin_hash,
232
+ "scan_result": self.scan_result.value,
233
+ "scanned_at": self.scanned_at.isoformat(),
234
+ "scanner_colony_id": self.scanner_colony_id,
235
+ }
236
+
237
+ def canonical_signing_bytes(self) -> bytes:
238
+ return json.dumps(
239
+ self.canonical_signing_dict(), sort_keys=True, separators=(",", ":")
240
+ ).encode()
241
+
242
+ def to_dict(self) -> Dict[str, Any]:
243
+ return {
244
+ "scanner_colony_id": self.scanner_colony_id,
245
+ "plugin_hash": self.plugin_hash,
246
+ "plugin_name": self.plugin_name,
247
+ "plugin_version": self.plugin_version,
248
+ "scan_result": self.scan_result.value,
249
+ "findings": [f.to_dict() for f in self.findings],
250
+ "findings_hash": self.findings_hash,
251
+ "scanner_version": self.scanner_version,
252
+ "scan_policy_version": self.scan_policy_version,
253
+ "scanned_at": self.scanned_at.isoformat(),
254
+ "container_image": self.container_image,
255
+ "stages_completed": self.stages_completed,
256
+ "scanner_signature": self.scanner_signature,
257
+ }
258
+
259
+
260
+ @dataclass
261
+ class PluginFlagPayload:
262
+ """Payload for a plugin_flag chain transaction."""
263
+ reporter_colony_id: str
264
+ plugin_hash: str
265
+ plugin_name: str
266
+ plugin_version: str
267
+ vulnerability_description: str
268
+ severity: FindingSeverity
269
+ evidence_hash: str # SHA-256 of evidence payload
270
+ reporter_signature: str = "" # filled by caller before submission
271
+ evidence_url: Optional[str] = None
272
+ cve_id: Optional[str] = None
273
+ affects_versions: List[str] = field(default_factory=list)
274
+
275
+ def canonical_signing_dict(self) -> Dict[str, Any]:
276
+ return {
277
+ "evidence_hash": self.evidence_hash,
278
+ "plugin_hash": self.plugin_hash,
279
+ "reporter_colony_id": self.reporter_colony_id,
280
+ "severity": self.severity.value,
281
+ "vulnerability_description": self.vulnerability_description,
282
+ }
283
+
284
+ def canonical_signing_bytes(self) -> bytes:
285
+ return json.dumps(
286
+ self.canonical_signing_dict(), sort_keys=True, separators=(",", ":")
287
+ ).encode()
288
+
289
+ def to_dict(self) -> Dict[str, Any]:
290
+ return {
291
+ "reporter_colony_id": self.reporter_colony_id,
292
+ "plugin_hash": self.plugin_hash,
293
+ "plugin_name": self.plugin_name,
294
+ "plugin_version": self.plugin_version,
295
+ "vulnerability_description": self.vulnerability_description,
296
+ "severity": self.severity.value,
297
+ "evidence_hash": self.evidence_hash,
298
+ "reporter_signature": self.reporter_signature,
299
+ "evidence_url": self.evidence_url,
300
+ "cve_id": self.cve_id,
301
+ "affects_versions": self.affects_versions,
302
+ }
303
+
304
+
305
+ # ---------------------------------------------------------------------------
306
+ # Chain state record
307
+ # ---------------------------------------------------------------------------
308
+
309
+ @dataclass
310
+ class PluginChainRecord:
311
+ """The authoritative on-chain state for a plugin version.
312
+
313
+ Maintained by ChainStateMachine as part of plugin_registry.
314
+ """
315
+ plugin_hash: str
316
+ name: str
317
+ version: str
318
+ publisher_id: str
319
+ published_at_height: int
320
+ status: PluginChainStatus = PluginChainStatus.PENDING_SCAN
321
+ attestations: List[Dict[str, Any]] = field(default_factory=list)
322
+ flags: List[Dict[str, Any]] = field(default_factory=list)
323
+ safe_consensus: float = 0.0
324
+ flag_count_trusted: int = 0
325
+ superseded_by: Optional[str] = None # plugin_hash of patched version
326
+ source_url: Optional[str] = None
327
+ capabilities: List[str] = field(default_factory=list)
328
+
329
+ def recompute_consensus(
330
+ self,
331
+ scanner_weights: Dict[str, float],
332
+ ) -> float:
333
+ """Recompute safe_consensus from current attestations.
334
+
335
+ Args:
336
+ scanner_weights: Map of scanner_colony_id -> weight (float).
337
+ Sentinels typically receive 2.0, trusted non-Sentinels 1.0,
338
+ unknown colonies 0.25.
339
+
340
+ Returns:
341
+ Updated safe_consensus score (0.0–1.0).
342
+ """
343
+ total = 0.0
344
+ safe = 0.0
345
+ for att in self.attestations:
346
+ w = scanner_weights.get(att["scanner_colony_id"], 0.25)
347
+ total += w
348
+ if att["scan_result"] == ScanResult.SAFE.value:
349
+ safe += w
350
+ self.safe_consensus = (safe / total) if total > 0 else 0.0
351
+ return self.safe_consensus
352
+
353
+ def has_sentinel_safe(self, sentinel_ids: frozenset) -> bool:
354
+ """Return True if at least one Sentinel has attested SAFE."""
355
+ for att in self.attestations:
356
+ if (
357
+ att["scanner_colony_id"] in sentinel_ids
358
+ and att["scan_result"] == ScanResult.SAFE.value
359
+ ):
360
+ return True
361
+ return False
362
+
363
+ def has_flagged_from_trusted(self, trusted_ids: frozenset) -> bool:
364
+ """Return True if any trusted colony has attested FLAGGED."""
365
+ for att in self.attestations:
366
+ if (
367
+ att["scanner_colony_id"] in trusted_ids
368
+ and att["scan_result"] == ScanResult.FLAGGED.value
369
+ ):
370
+ return True
371
+ return False
@@ -0,0 +1,220 @@
1
+ """Protocol message types for ColonyChain inter-node communication.
2
+
3
+ Defines the wire format for chain sync, block announcement,
4
+ admin commands, and network broadcasts.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ from dataclasses import dataclass, field
11
+ from datetime import datetime, timezone
12
+ from enum import Enum
13
+ from typing import Any
14
+
15
+
16
+ class ChainMsgType(str, Enum):
17
+ """Chain protocol message types."""
18
+ CHAIN_SYNC = "CHAIN_SYNC" # Request blocks from a range
19
+ CHAIN_SYNC_RESPONSE = "CHAIN_SYNC_RESPONSE" # Response carrying blocks
20
+ CHAIN_ANNOUNCE = "CHAIN_ANNOUNCE" # Broadcast new block
21
+ ADMIN_COMMAND = "ADMIN_COMMAND" # Genesis admin messages
22
+ BROADCAST = "BROADCAST" # Network-wide announcements
23
+ CHAIN_STATE_REQUEST = "CHAIN_STATE_REQUEST" # Request current chain state
24
+ CHAIN_STATE_RESPONSE = "CHAIN_STATE_RESPONSE" # Response with chain state summary
25
+ TX_SUBMIT = "TX_SUBMIT" # Submit transaction to mempool
26
+ TX_SUBMIT_RESPONSE = "TX_SUBMIT_RESPONSE" # Ack/nack for tx submission
27
+
28
+
29
+ @dataclass
30
+ class ChainSyncRequest:
31
+ """Request blocks from a range [from_index, to_index]."""
32
+ from_index: int
33
+ to_index: int
34
+ requester_id: str
35
+
36
+ def to_dict(self) -> dict[str, Any]:
37
+ return {
38
+ "type": ChainMsgType.CHAIN_SYNC.value,
39
+ "from_index": self.from_index,
40
+ "to_index": self.to_index,
41
+ "requester_id": self.requester_id,
42
+ }
43
+
44
+ @classmethod
45
+ def from_dict(cls, d: dict[str, Any]) -> "ChainSyncRequest":
46
+ return cls(
47
+ from_index=d["from_index"],
48
+ to_index=d["to_index"],
49
+ requester_id=d.get("requester_id", ""),
50
+ )
51
+
52
+
53
+ @dataclass
54
+ class ChainSyncResponse:
55
+ """Response carrying a list of serialized blocks."""
56
+ blocks: list[dict[str, Any]]
57
+ from_index: int
58
+ to_index: int
59
+ responder_id: str
60
+
61
+ def to_dict(self) -> dict[str, Any]:
62
+ return {
63
+ "type": ChainMsgType.CHAIN_SYNC_RESPONSE.value,
64
+ "blocks": self.blocks,
65
+ "from_index": self.from_index,
66
+ "to_index": self.to_index,
67
+ "responder_id": self.responder_id,
68
+ }
69
+
70
+
71
+ @dataclass
72
+ class ChainAnnouncement:
73
+ """Broadcast that a new block has been committed."""
74
+ block_index: int
75
+ block_hash: str
76
+ producer_id: str
77
+ timestamp: str = field(
78
+ default_factory=lambda: datetime.now(timezone.utc).isoformat()
79
+ )
80
+ tx_count: int = 0
81
+
82
+ def to_dict(self) -> dict[str, Any]:
83
+ return {
84
+ "type": ChainMsgType.CHAIN_ANNOUNCE.value,
85
+ "block_index": self.block_index,
86
+ "block_hash": self.block_hash,
87
+ "producer_id": self.producer_id,
88
+ "timestamp": self.timestamp,
89
+ "tx_count": self.tx_count,
90
+ }
91
+
92
+ @classmethod
93
+ def from_dict(cls, d: dict[str, Any]) -> "ChainAnnouncement":
94
+ return cls(
95
+ block_index=d["block_index"],
96
+ block_hash=d["block_hash"],
97
+ producer_id=d["producer_id"],
98
+ timestamp=d.get("timestamp", ""),
99
+ tx_count=d.get("tx_count", 0),
100
+ )
101
+
102
+
103
+ @dataclass
104
+ class AdminCommand:
105
+ """Genesis admin command message (signed)."""
106
+ command_type: str # "suspend" | "reinstate" | "sentinel_appoint" | etc.
107
+ target_id: str
108
+ genesis_colony_id: str
109
+ signed_tx_json: str # JSON of the signed Transaction
110
+ timestamp: str = field(
111
+ default_factory=lambda: datetime.now(timezone.utc).isoformat()
112
+ )
113
+
114
+ def to_dict(self) -> dict[str, Any]:
115
+ return {
116
+ "type": ChainMsgType.ADMIN_COMMAND.value,
117
+ "command_type": self.command_type,
118
+ "target_id": self.target_id,
119
+ "genesis_colony_id": self.genesis_colony_id,
120
+ "signed_tx_json": self.signed_tx_json,
121
+ "timestamp": self.timestamp,
122
+ }
123
+
124
+
125
+ @dataclass
126
+ class BroadcastMessage:
127
+ """Network-wide announcement from Genesis admin."""
128
+ sender_id: str
129
+ message: str
130
+ signed_tx_json: str
131
+ timestamp: str = field(
132
+ default_factory=lambda: datetime.now(timezone.utc).isoformat()
133
+ )
134
+
135
+ def to_dict(self) -> dict[str, Any]:
136
+ return {
137
+ "type": ChainMsgType.BROADCAST.value,
138
+ "sender_id": self.sender_id,
139
+ "message": self.message,
140
+ "signed_tx_json": self.signed_tx_json,
141
+ "timestamp": self.timestamp,
142
+ }
143
+
144
+
145
+ @dataclass
146
+ class ChainStateRequest:
147
+ """Request a summary of the current chain state from a Sentinel."""
148
+ requester_id: str
149
+
150
+ def to_dict(self) -> dict[str, Any]:
151
+ return {
152
+ "type": ChainMsgType.CHAIN_STATE_REQUEST.value,
153
+ "requester_id": self.requester_id,
154
+ }
155
+
156
+
157
+ @dataclass
158
+ class ChainStateResponse:
159
+ """Summary of current chain state."""
160
+ height: int
161
+ last_block_hash: str
162
+ n_colonies: int
163
+ n_sentinels: int
164
+ n_suspended: int
165
+ network_id: str
166
+ responder_id: str
167
+
168
+ def to_dict(self) -> dict[str, Any]:
169
+ return {
170
+ "type": ChainMsgType.CHAIN_STATE_RESPONSE.value,
171
+ "height": self.height,
172
+ "last_block_hash": self.last_block_hash,
173
+ "n_colonies": self.n_colonies,
174
+ "n_sentinels": self.n_sentinels,
175
+ "n_suspended": self.n_suspended,
176
+ "network_id": self.network_id,
177
+ "responder_id": self.responder_id,
178
+ }
179
+
180
+ @classmethod
181
+ def from_dict(cls, d: dict[str, Any]) -> "ChainStateResponse":
182
+ return cls(
183
+ height=d["height"],
184
+ last_block_hash=d["last_block_hash"],
185
+ n_colonies=d["n_colonies"],
186
+ n_sentinels=d["n_sentinels"],
187
+ n_suspended=d["n_suspended"],
188
+ network_id=d.get("network_id", ""),
189
+ responder_id=d.get("responder_id", ""),
190
+ )
191
+
192
+
193
+ @dataclass
194
+ class TxSubmitRequest:
195
+ """Submit a signed transaction to a Sentinel's mempool."""
196
+ tx_json: str
197
+ submitter_id: str
198
+
199
+ def to_dict(self) -> dict[str, Any]:
200
+ return {
201
+ "type": ChainMsgType.TX_SUBMIT.value,
202
+ "tx_json": self.tx_json,
203
+ "submitter_id": self.submitter_id,
204
+ }
205
+
206
+
207
+ @dataclass
208
+ class TxSubmitResponse:
209
+ """Acknowledgment or rejection of a submitted transaction."""
210
+ tx_id: str
211
+ accepted: bool
212
+ reason: str = ""
213
+
214
+ def to_dict(self) -> dict[str, Any]:
215
+ return {
216
+ "type": ChainMsgType.TX_SUBMIT_RESPONSE.value,
217
+ "tx_id": self.tx_id,
218
+ "accepted": self.accepted,
219
+ "reason": self.reason,
220
+ }