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,3530 @@
1
+ """P7 owner-visible drives and immutable charter governance.
2
+
3
+ This module is a side-effect-free priority layer around P3's goal spine. It
4
+ does not create projects, execute actions, or mint authority. A ranking is
5
+ considered eligible only after the server resolves all five persisted P3
6
+ policy decisions, and every result explicitly declares that it has no
7
+ authorization effect.
8
+
9
+ Charter changes reuse Colony's transport-neutral ``ApprovalAuthorityStore``.
10
+ Models may propose immutable revisions, but activation and revocation require
11
+ an exact, unexpired approval request plus the server-derived scoped owner
12
+ ``RequestAuthority``. Lifecycle state is append-only and every proposal and
13
+ ratification operation is replay fenced.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from dataclasses import asdict, dataclass
19
+ from datetime import datetime, timedelta, timezone
20
+ import hashlib
21
+ import json
22
+ import os
23
+ from pathlib import Path
24
+ import re
25
+ import sqlite3
26
+ import threading
27
+ from typing import Any, Callable, Dict, Iterable, Mapping, Optional, Sequence
28
+
29
+ from apsimo.initiatives.approval_authority import (
30
+ ActionBinding,
31
+ ApprovalAuthorityStore,
32
+ ApprovalSubjectBinding,
33
+ PRESENTATION_SCHEMA,
34
+ )
35
+ from apsimo.scope_bounds import VIEWER_SCOPE_MAX_CHARS
36
+
37
+
38
+ DRIVE_GOVERNANCE_SCHEMA_VERSION = 7
39
+ _MODES = frozenset({"off", "shadow", "bootstrap", "live"})
40
+ _SHAREABILITY = frozenset({
41
+ "owner_private", "subject_private", "shared", "public",
42
+ })
43
+ _DRIVE_STATES = frozenset({"enabled", "disabled"})
44
+ _SIGNAL_STATES = frozenset({"active", "disabled", "unknown"})
45
+ _TRANSITIONS = frozenset({"activate", "revoke"})
46
+ CHARTER_TRANSITION_APPROVAL_PROJECTION_SCHEMA = (
47
+ "ColonyCharterTransitionApprovalProjectionV1"
48
+ )
49
+ _REQUIRED_P3_STAGES = (
50
+ "charter", "boundary", "situation", "duplicate", "authority",
51
+ )
52
+ _SAFE_ID = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.:@/+\-]{0,255}$")
53
+ _SAFE_KEY = re.compile(r"^[a-z][a-z0-9_.-]{0,63}$")
54
+ _SECRET_ASSIGNMENT = re.compile(
55
+ r"(?i)\b(api[_-]?key|authorization|bearer|credential|password|secret|token)"
56
+ r"\s*[:=]\s*(?:bearer\s+)?[^\s,;]+"
57
+ )
58
+
59
+
60
+ class DriveGovernanceError(ValueError):
61
+ """Stable, public-safe governance failure."""
62
+
63
+ def __init__(self, code: str, message: str) -> None:
64
+ super().__init__(message)
65
+ self.code = code
66
+ self.message = message
67
+
68
+
69
+ def drive_governance_mode() -> str:
70
+ """Return the explicit migration mode; unset/invalid always fails off."""
71
+
72
+ value = os.environ.get("COLONY_DRIVE_GOVERNANCE_MODE", "off").strip().lower()
73
+ return value if value in _MODES else "off"
74
+
75
+
76
+ def _normalized_mode(value: Optional[str]) -> str:
77
+ if value is None:
78
+ return drive_governance_mode()
79
+ normalized = str(value).strip().lower()
80
+ return normalized if normalized in _MODES else "off"
81
+
82
+
83
+ def _canonical(value: Any) -> str:
84
+ def default(item: Any) -> str:
85
+ if isinstance(item, datetime):
86
+ return _iso(item)
87
+ return str(item)
88
+
89
+ return json.dumps(
90
+ value,
91
+ sort_keys=True,
92
+ separators=(",", ":"),
93
+ ensure_ascii=False,
94
+ default=default,
95
+ )
96
+
97
+
98
+ def _digest(value: Any) -> str:
99
+ return hashlib.sha256(_canonical(value).encode("utf-8")).hexdigest()
100
+
101
+
102
+ def _as_utc(value: Optional[datetime]) -> datetime:
103
+ result = value or datetime.now(timezone.utc)
104
+ if result.tzinfo is None:
105
+ result = result.replace(tzinfo=timezone.utc)
106
+ return result.astimezone(timezone.utc)
107
+
108
+
109
+ def _iso(value: datetime) -> str:
110
+ return _as_utc(value).isoformat()
111
+
112
+
113
+ def _parse_time(value: Any, *, field: str) -> datetime:
114
+ if isinstance(value, datetime):
115
+ return _as_utc(value)
116
+ text = str(value or "").strip()
117
+ if text.endswith("Z"):
118
+ text = text[:-1] + "+00:00"
119
+ try:
120
+ parsed = datetime.fromisoformat(text)
121
+ except (TypeError, ValueError) as exc:
122
+ raise DriveGovernanceError(
123
+ "invalid_time", f"{field} must be an RFC3339 timestamp",
124
+ ) from exc
125
+ if parsed.tzinfo is None:
126
+ raise DriveGovernanceError(
127
+ "invalid_time", f"{field} must include a timezone",
128
+ )
129
+ return parsed.astimezone(timezone.utc)
130
+
131
+
132
+ def _text(value: Any, field: str, maximum: int, *, required: bool = True) -> str:
133
+ result = " ".join(str(value or "").split()).strip()
134
+ if required and not result:
135
+ raise DriveGovernanceError("invalid_text", f"{field} is required")
136
+ if len(result) > maximum:
137
+ raise DriveGovernanceError(
138
+ "invalid_text", f"{field} exceeds {maximum} characters",
139
+ )
140
+ return _SECRET_ASSIGNMENT.sub(
141
+ lambda match: f"{match.group(1)}=[REDACTED]", result,
142
+ )
143
+
144
+
145
+ def _identifier(value: Any, field: str, *, maximum: int = 256) -> str:
146
+ result = str(value or "").strip()
147
+ if len(result) > maximum or not _SAFE_ID.fullmatch(result):
148
+ raise DriveGovernanceError("invalid_identifier", f"{field} is invalid")
149
+ return result
150
+
151
+
152
+ def _operation_id(value: Any) -> str:
153
+ result = _identifier(value, "operation_id")
154
+ if len(result) < 8:
155
+ raise DriveGovernanceError(
156
+ "invalid_operation_id", "operation_id must be at least 8 characters",
157
+ )
158
+ return result
159
+
160
+
161
+ def _refs(
162
+ values: Iterable[Any],
163
+ *,
164
+ field: str = "evidence_refs",
165
+ maximum: int = 40,
166
+ required: bool = False,
167
+ ) -> tuple[str, ...]:
168
+ result: list[str] = []
169
+ for raw in values or ():
170
+ value = str(raw or "").strip()
171
+ if not _SAFE_ID.fullmatch(value):
172
+ raise DriveGovernanceError(
173
+ "invalid_evidence", f"{field} contains an invalid reference",
174
+ )
175
+ if value not in result:
176
+ result.append(value)
177
+ if len(result) > maximum:
178
+ raise DriveGovernanceError(
179
+ "evidence_budget_exceeded",
180
+ f"{field} exceeds {maximum} references",
181
+ )
182
+ if required and not result:
183
+ raise DriveGovernanceError(
184
+ "evidence_required", f"{field} requires evidence",
185
+ )
186
+ return tuple(result)
187
+
188
+
189
+ def _bounded_float(
190
+ value: Any,
191
+ field: str,
192
+ *,
193
+ minimum: float,
194
+ maximum: float,
195
+ ) -> float:
196
+ if isinstance(value, bool):
197
+ raise DriveGovernanceError("invalid_number", f"{field} must be numeric")
198
+ try:
199
+ result = float(value)
200
+ except (TypeError, ValueError) as exc:
201
+ raise DriveGovernanceError(
202
+ "invalid_number", f"{field} must be numeric",
203
+ ) from exc
204
+ if not minimum <= result <= maximum:
205
+ raise DriveGovernanceError(
206
+ "invalid_number", f"{field} must be between {minimum} and {maximum}",
207
+ )
208
+ return round(result, 8)
209
+
210
+
211
+ def _bounded_int(value: Any, field: str, *, minimum: int, maximum: int) -> int:
212
+ if isinstance(value, bool):
213
+ raise DriveGovernanceError("invalid_number", f"{field} must be an integer")
214
+ try:
215
+ result = int(value)
216
+ except (TypeError, ValueError) as exc:
217
+ raise DriveGovernanceError(
218
+ "invalid_number", f"{field} must be an integer",
219
+ ) from exc
220
+ if result != value and not isinstance(value, str):
221
+ raise DriveGovernanceError("invalid_number", f"{field} must be an integer")
222
+ if not minimum <= result <= maximum:
223
+ raise DriveGovernanceError(
224
+ "invalid_number", f"{field} must be between {minimum} and {maximum}",
225
+ )
226
+ return result
227
+
228
+
229
+ @dataclass(frozen=True)
230
+ class ScopeV1:
231
+ """Scope carried from evidence through signals and ranking projections."""
232
+
233
+ subject_person_id: str
234
+ viewer_scope: str
235
+ shareability: str
236
+ schema: str = "ScopeV1"
237
+ version: int = 1
238
+
239
+ def __post_init__(self) -> None:
240
+ _identifier(self.subject_person_id, "subject_person_id", maximum=128)
241
+ _identifier(
242
+ self.viewer_scope, "viewer_scope",
243
+ maximum=VIEWER_SCOPE_MAX_CHARS,
244
+ )
245
+ if self.shareability not in _SHAREABILITY:
246
+ raise DriveGovernanceError(
247
+ "invalid_scope", "shareability is not recognized",
248
+ )
249
+ expected = {
250
+ "owner_private": "owner",
251
+ "subject_private": f"person:{self.subject_person_id}",
252
+ "shared": "shared",
253
+ "public": "public",
254
+ }[self.shareability]
255
+ if self.viewer_scope != expected:
256
+ raise DriveGovernanceError(
257
+ "invalid_scope",
258
+ "viewer_scope must match the declared shareability lane",
259
+ )
260
+
261
+ def payload(self) -> Dict[str, Any]:
262
+ return asdict(self)
263
+
264
+ def visible_to(
265
+ self,
266
+ *,
267
+ viewer_person_id: str,
268
+ owner_person_id: str,
269
+ audiences: set[str] | frozenset[str] = frozenset(),
270
+ ) -> bool:
271
+ viewer = str(viewer_person_id or "").strip()
272
+ owner = str(owner_person_id or "").strip()
273
+ if not viewer:
274
+ return False
275
+ if owner and viewer == owner:
276
+ return True
277
+ if self.shareability == "public":
278
+ return "global" in audiences
279
+ if self.shareability == "shared":
280
+ return "shared" in audiences
281
+ if self.shareability == "subject_private":
282
+ return viewer == self.subject_person_id
283
+ return False
284
+
285
+ def permits_child(self, child: "ScopeV1") -> bool:
286
+ """Return whether ``child`` is no broader than this scope."""
287
+
288
+ if self.shareability == "public":
289
+ return True
290
+ if self.shareability == "shared":
291
+ return child.shareability in {
292
+ "shared", "owner_private",
293
+ }
294
+ if self.shareability == "owner_private":
295
+ return child.shareability == "owner_private"
296
+ return (
297
+ child.shareability == "owner_private"
298
+ or (
299
+ child.shareability == "subject_private"
300
+ and child.subject_person_id == self.subject_person_id
301
+ )
302
+ )
303
+
304
+
305
+ def _narrower_scope(first: ScopeV1, second: ScopeV1) -> ScopeV1:
306
+ if first.permits_child(second):
307
+ return second
308
+ if second.permits_child(first):
309
+ return first
310
+ # Incomparable private lanes can only be combined into an owner-visible
311
+ # projection; this prevents a score from leaking that a private signal
312
+ # exists to either subject.
313
+ subject = first.subject_person_id or second.subject_person_id
314
+ return ScopeV1(subject, "owner", "owner_private")
315
+
316
+
317
+ @dataclass(frozen=True)
318
+ class RankingBudgetV1:
319
+ max_goals: int = 50
320
+ max_signals_per_drive: int = 5
321
+ max_total_signals: int = 250
322
+ max_evidence_refs_per_goal: int = 20
323
+ schema: str = "RankingBudgetV1"
324
+ version: int = 1
325
+
326
+ def __post_init__(self) -> None:
327
+ object.__setattr__(
328
+ self, "max_goals",
329
+ _bounded_int(self.max_goals, "max_goals", minimum=1, maximum=200),
330
+ )
331
+ object.__setattr__(
332
+ self, "max_signals_per_drive",
333
+ _bounded_int(
334
+ self.max_signals_per_drive,
335
+ "max_signals_per_drive", minimum=1, maximum=20,
336
+ ),
337
+ )
338
+ object.__setattr__(
339
+ self, "max_total_signals",
340
+ _bounded_int(
341
+ self.max_total_signals,
342
+ "max_total_signals", minimum=1, maximum=2000,
343
+ ),
344
+ )
345
+ object.__setattr__(
346
+ self, "max_evidence_refs_per_goal",
347
+ _bounded_int(
348
+ self.max_evidence_refs_per_goal,
349
+ "max_evidence_refs_per_goal", minimum=1, maximum=100,
350
+ ),
351
+ )
352
+
353
+ def payload(self) -> Dict[str, Any]:
354
+ return asdict(self)
355
+
356
+
357
+ @dataclass(frozen=True)
358
+ class DriveV1:
359
+ drive_id: str
360
+ definition_digest: str
361
+ key: str
362
+ version_label: str
363
+ title: str
364
+ definition_summary: str
365
+ max_abs_contribution: float
366
+ max_signals_per_goal: int
367
+ state: str
368
+ scope: ScopeV1
369
+ evidence_refs: tuple[str, ...]
370
+ created_at: str
371
+ expires_at: Optional[str]
372
+ schema: str = "DriveV1"
373
+ version: int = 1
374
+
375
+ @classmethod
376
+ def create(
377
+ cls,
378
+ *,
379
+ key: str,
380
+ version: str,
381
+ title: str,
382
+ definition_summary: str,
383
+ max_abs_contribution: float,
384
+ max_signals_per_goal: int,
385
+ state: str,
386
+ scope: ScopeV1,
387
+ evidence_refs: Iterable[str],
388
+ created_at: Optional[datetime] = None,
389
+ expires_at: Optional[datetime] = None,
390
+ ) -> "DriveV1":
391
+ key = str(key or "").strip().lower()
392
+ if not _SAFE_KEY.fullmatch(key):
393
+ raise DriveGovernanceError("invalid_drive_key", "drive key is invalid")
394
+ version_label = _identifier(version, "drive version", maximum=32)
395
+ normalized_state = str(state or "").strip().lower()
396
+ if normalized_state not in _DRIVE_STATES:
397
+ raise DriveGovernanceError("invalid_drive_state", "drive state is invalid")
398
+ created = _as_utc(created_at)
399
+ expiry = _as_utc(expires_at) if expires_at is not None else None
400
+ if expiry is not None and expiry <= created:
401
+ raise DriveGovernanceError(
402
+ "invalid_expiry", "drive expiry must follow creation",
403
+ )
404
+ authority = {
405
+ "schema": "DriveV1", "version": 1,
406
+ "key": key,
407
+ "version_label": version_label,
408
+ "title": _text(title, "title", 120),
409
+ "definition_summary": _text(
410
+ definition_summary, "definition_summary", 600,
411
+ ),
412
+ "max_abs_contribution": _bounded_float(
413
+ max_abs_contribution, "max_abs_contribution",
414
+ minimum=0.0, maximum=1.0,
415
+ ),
416
+ "max_signals_per_goal": _bounded_int(
417
+ max_signals_per_goal, "max_signals_per_goal",
418
+ minimum=1, maximum=20,
419
+ ),
420
+ "state": normalized_state,
421
+ "scope": scope.payload(),
422
+ "evidence_refs": list(_refs(
423
+ evidence_refs, required=True, maximum=20,
424
+ )),
425
+ "created_at": _iso(created),
426
+ "expires_at": _iso(expiry) if expiry else None,
427
+ }
428
+ digest = _digest(authority)
429
+ return cls(
430
+ drive_id=f"drive:{key}:{digest[:20]}",
431
+ definition_digest=digest,
432
+ key=key,
433
+ version_label=version_label,
434
+ title=authority["title"],
435
+ definition_summary=authority["definition_summary"],
436
+ max_abs_contribution=authority["max_abs_contribution"],
437
+ max_signals_per_goal=authority["max_signals_per_goal"],
438
+ state=normalized_state,
439
+ scope=scope,
440
+ evidence_refs=tuple(authority["evidence_refs"]),
441
+ created_at=authority["created_at"],
442
+ expires_at=authority["expires_at"],
443
+ )
444
+
445
+ def authority_payload(self) -> Dict[str, Any]:
446
+ return {
447
+ "schema": self.schema, "version": self.version,
448
+ "key": self.key,
449
+ "version_label": self.version_label,
450
+ "title": self.title,
451
+ "definition_summary": self.definition_summary,
452
+ "max_abs_contribution": self.max_abs_contribution,
453
+ "max_signals_per_goal": self.max_signals_per_goal,
454
+ "state": self.state,
455
+ "scope": self.scope.payload(),
456
+ "evidence_refs": list(self.evidence_refs),
457
+ "created_at": self.created_at,
458
+ "expires_at": self.expires_at,
459
+ }
460
+
461
+ def payload(self) -> Dict[str, Any]:
462
+ return {
463
+ **self.authority_payload(),
464
+ "drive_id": self.drive_id,
465
+ "definition_digest": self.definition_digest,
466
+ }
467
+
468
+ def validate_integrity(self) -> None:
469
+ if self.schema != "DriveV1" or self.version != 1:
470
+ raise DriveGovernanceError(
471
+ "unsupported_schema", "drive definition schema is unsupported",
472
+ )
473
+ if not _SAFE_KEY.fullmatch(str(self.key or "")):
474
+ raise DriveGovernanceError("invalid_drive_key", "drive key is invalid")
475
+ _identifier(self.version_label, "drive version", maximum=32)
476
+ if _text(self.title, "title", 120) != self.title or _text(
477
+ self.definition_summary, "definition_summary", 600,
478
+ ) != self.definition_summary:
479
+ raise DriveGovernanceError(
480
+ "invalid_text", "drive text is not normalized and bounded",
481
+ )
482
+ if self.state not in _DRIVE_STATES:
483
+ raise DriveGovernanceError("invalid_drive_state", "drive state is invalid")
484
+ _bounded_float(
485
+ self.max_abs_contribution, "max_abs_contribution",
486
+ minimum=0.0, maximum=1.0,
487
+ )
488
+ _bounded_int(
489
+ self.max_signals_per_goal, "max_signals_per_goal",
490
+ minimum=1, maximum=20,
491
+ )
492
+ if _refs(
493
+ self.evidence_refs, required=True, maximum=20,
494
+ ) != self.evidence_refs:
495
+ raise DriveGovernanceError(
496
+ "invalid_evidence", "drive evidence references are not canonical",
497
+ )
498
+ created = _parse_time(self.created_at, field="drive created_at")
499
+ if self.expires_at and _parse_time(
500
+ self.expires_at, field="drive expires_at",
501
+ ) <= created:
502
+ raise DriveGovernanceError(
503
+ "invalid_expiry", "drive expiry must follow creation",
504
+ )
505
+ digest = _digest(self.authority_payload())
506
+ if digest != self.definition_digest\
507
+ or self.drive_id != f"drive:{self.key}:{digest[:20]}":
508
+ raise DriveGovernanceError(
509
+ "immutable_object_tampered", "drive definition integrity mismatch",
510
+ )
511
+
512
+ def state_at(self, now: Optional[datetime] = None) -> str:
513
+ if self.state == "disabled":
514
+ return "disabled"
515
+ if self.expires_at and _parse_time(
516
+ self.expires_at, field="drive expires_at",
517
+ ) <= _as_utc(now):
518
+ return "expired"
519
+ return "enabled"
520
+
521
+ @classmethod
522
+ def from_payload(cls, payload: Mapping[str, Any]) -> "DriveV1":
523
+ result = cls(
524
+ drive_id=str(payload["drive_id"]),
525
+ definition_digest=str(payload["definition_digest"]),
526
+ key=str(payload["key"]),
527
+ version_label=str(payload["version_label"]),
528
+ title=str(payload["title"]),
529
+ definition_summary=str(payload["definition_summary"]),
530
+ max_abs_contribution=float(payload["max_abs_contribution"]),
531
+ max_signals_per_goal=int(payload["max_signals_per_goal"]),
532
+ state=str(payload["state"]),
533
+ scope=ScopeV1(**dict(payload["scope"])),
534
+ evidence_refs=tuple(payload.get("evidence_refs") or ()),
535
+ created_at=str(payload["created_at"]),
536
+ expires_at=(
537
+ str(payload["expires_at"]) if payload.get("expires_at") else None
538
+ ),
539
+ )
540
+ result.validate_integrity()
541
+ return result
542
+
543
+
544
+ @dataclass(frozen=True)
545
+ class DriveSignalV1:
546
+ signal_id: str
547
+ signal_digest: str
548
+ drive_id: str
549
+ goal_fingerprint: str
550
+ normalized_value: float
551
+ confidence: float
552
+ state: str
553
+ rationale_summary: str
554
+ evidence_refs: tuple[str, ...]
555
+ observed_at: str
556
+ expires_at: str
557
+ scope: ScopeV1
558
+ schema: str = "DriveSignalV1"
559
+ version: int = 1
560
+
561
+ @classmethod
562
+ def derive(
563
+ cls,
564
+ *,
565
+ drive: DriveV1,
566
+ goal_fingerprint: str,
567
+ normalized_value: float,
568
+ confidence: float,
569
+ rationale_summary: str,
570
+ evidence_refs: Iterable[str],
571
+ observed_at: datetime,
572
+ expires_at: datetime,
573
+ scope: ScopeV1,
574
+ state: str = "active",
575
+ ) -> "DriveSignalV1":
576
+ drive.validate_integrity()
577
+ fingerprint = _identifier(
578
+ goal_fingerprint, "goal_fingerprint", maximum=192,
579
+ )
580
+ normalized_state = str(state or "").strip().lower()
581
+ if normalized_state not in _SIGNAL_STATES:
582
+ raise DriveGovernanceError(
583
+ "invalid_signal_state", "signal state is invalid",
584
+ )
585
+ if not drive.scope.permits_child(scope):
586
+ raise DriveGovernanceError(
587
+ "scope_broadening", "signal scope cannot broaden its drive scope",
588
+ )
589
+ observed = _as_utc(observed_at)
590
+ expiry = _as_utc(expires_at)
591
+ if expiry <= observed:
592
+ raise DriveGovernanceError(
593
+ "invalid_expiry", "signal expiry must follow observation",
594
+ )
595
+ if expiry - observed > timedelta(days=90):
596
+ raise DriveGovernanceError(
597
+ "invalid_expiry", "signal lifetime cannot exceed 90 days",
598
+ )
599
+ value = _bounded_float(
600
+ normalized_value, "normalized_value", minimum=-1.0, maximum=1.0,
601
+ )
602
+ if normalized_state != "active" and value != 0.0:
603
+ # Disabled/unknown evidence is explicit state, not a hidden score.
604
+ value = 0.0
605
+ authority = {
606
+ "schema": "DriveSignalV1", "version": 1,
607
+ "drive_id": drive.drive_id,
608
+ "goal_fingerprint": fingerprint,
609
+ "normalized_value": value,
610
+ "confidence": _bounded_float(
611
+ confidence, "confidence", minimum=0.0, maximum=1.0,
612
+ ),
613
+ "state": normalized_state,
614
+ "rationale_summary": _text(
615
+ rationale_summary, "rationale_summary", 500,
616
+ ),
617
+ "evidence_refs": list(_refs(
618
+ evidence_refs, required=True, maximum=20,
619
+ )),
620
+ "observed_at": _iso(observed),
621
+ "expires_at": _iso(expiry),
622
+ "scope": scope.payload(),
623
+ }
624
+ digest = _digest(authority)
625
+ return cls(
626
+ signal_id=f"drive-signal:{digest[:24]}",
627
+ signal_digest=digest,
628
+ drive_id=drive.drive_id,
629
+ goal_fingerprint=fingerprint,
630
+ normalized_value=value,
631
+ confidence=authority["confidence"],
632
+ state=normalized_state,
633
+ rationale_summary=authority["rationale_summary"],
634
+ evidence_refs=tuple(authority["evidence_refs"]),
635
+ observed_at=authority["observed_at"],
636
+ expires_at=authority["expires_at"],
637
+ scope=scope,
638
+ )
639
+
640
+ def authority_payload(self) -> Dict[str, Any]:
641
+ return {
642
+ "schema": self.schema, "version": self.version,
643
+ "drive_id": self.drive_id,
644
+ "goal_fingerprint": self.goal_fingerprint,
645
+ "normalized_value": self.normalized_value,
646
+ "confidence": self.confidence,
647
+ "state": self.state,
648
+ "rationale_summary": self.rationale_summary,
649
+ "evidence_refs": list(self.evidence_refs),
650
+ "observed_at": self.observed_at,
651
+ "expires_at": self.expires_at,
652
+ "scope": self.scope.payload(),
653
+ }
654
+
655
+ def payload(self) -> Dict[str, Any]:
656
+ return {
657
+ **self.authority_payload(),
658
+ "signal_id": self.signal_id,
659
+ "signal_digest": self.signal_digest,
660
+ }
661
+
662
+ def validate_integrity(self) -> None:
663
+ if self.schema != "DriveSignalV1" or self.version != 1:
664
+ raise DriveGovernanceError(
665
+ "unsupported_schema", "drive signal schema is unsupported",
666
+ )
667
+ _identifier(self.drive_id, "drive_id")
668
+ _identifier(self.goal_fingerprint, "goal_fingerprint", maximum=192)
669
+ if self.state not in _SIGNAL_STATES:
670
+ raise DriveGovernanceError(
671
+ "invalid_signal_state", "signal state is invalid",
672
+ )
673
+ value = _bounded_float(
674
+ self.normalized_value, "normalized_value",
675
+ minimum=-1.0, maximum=1.0,
676
+ )
677
+ _bounded_float(self.confidence, "confidence", minimum=0.0, maximum=1.0)
678
+ if self.state != "active" and value != 0.0:
679
+ raise DriveGovernanceError(
680
+ "invalid_signal_state",
681
+ "disabled or unknown signals cannot carry a score",
682
+ )
683
+ if _text(
684
+ self.rationale_summary, "rationale_summary", 500,
685
+ ) != self.rationale_summary:
686
+ raise DriveGovernanceError(
687
+ "invalid_text", "signal rationale is not normalized and bounded",
688
+ )
689
+ if _refs(
690
+ self.evidence_refs, required=True, maximum=20,
691
+ ) != self.evidence_refs:
692
+ raise DriveGovernanceError(
693
+ "invalid_evidence", "signal evidence references are not canonical",
694
+ )
695
+ observed = _parse_time(self.observed_at, field="signal observed_at")
696
+ expiry = _parse_time(self.expires_at, field="signal expires_at")
697
+ if expiry <= observed or expiry - observed > timedelta(days=90):
698
+ raise DriveGovernanceError(
699
+ "invalid_expiry", "signal expiry is outside its bounded lifetime",
700
+ )
701
+ digest = _digest(self.authority_payload())
702
+ if digest != self.signal_digest\
703
+ or self.signal_id != f"drive-signal:{digest[:24]}":
704
+ raise DriveGovernanceError(
705
+ "immutable_object_tampered", "drive signal integrity mismatch",
706
+ )
707
+
708
+ def state_at(self, now: Optional[datetime] = None) -> str:
709
+ if _parse_time(self.expires_at, field="signal expires_at") <= _as_utc(now):
710
+ return "expired"
711
+ return self.state
712
+
713
+ @classmethod
714
+ def from_payload(cls, payload: Mapping[str, Any]) -> "DriveSignalV1":
715
+ result = cls(
716
+ signal_id=str(payload["signal_id"]),
717
+ signal_digest=str(payload["signal_digest"]),
718
+ drive_id=str(payload["drive_id"]),
719
+ goal_fingerprint=str(payload["goal_fingerprint"]),
720
+ normalized_value=float(payload["normalized_value"]),
721
+ confidence=float(payload["confidence"]),
722
+ state=str(payload["state"]),
723
+ rationale_summary=str(payload["rationale_summary"]),
724
+ evidence_refs=tuple(payload.get("evidence_refs") or ()),
725
+ observed_at=str(payload["observed_at"]),
726
+ expires_at=str(payload["expires_at"]),
727
+ scope=ScopeV1(**dict(payload["scope"])),
728
+ )
729
+ result.validate_integrity()
730
+ return result
731
+
732
+
733
+ @dataclass(frozen=True)
734
+ class CharterAdmissionConstraintsV1:
735
+ """Deterministic upper bounds for P3 admission under one charter."""
736
+
737
+ objective_allow_terms: tuple[str, ...] = ()
738
+ objective_deny_terms: tuple[str, ...] = (
739
+ "destroy", "drop", "format", "overwrite", "wipe",
740
+ )
741
+ capability_ceiling: tuple[str, ...] = (
742
+ "concerns:read", "directives:read", "memory:read",
743
+ "projects:read", "reasoning", "situation:read", "web:read",
744
+ "world_model:read",
745
+ )
746
+ capability_deny: tuple[str, ...] = ("messaging:send", "root:shell")
747
+ required_boundary_refs: tuple[str, ...] = ()
748
+ allowed_shareability: tuple[str, ...] = ("owner_private",)
749
+ allowed_recipient_ids: tuple[str, ...] = ()
750
+ allow_destructive: bool = False
751
+ allow_root_shell: bool = False
752
+ allow_messaging: bool = False
753
+ schema: str = "CharterAdmissionConstraintsV1"
754
+ version: int = 1
755
+
756
+ def __post_init__(self) -> None:
757
+ if self.schema != "CharterAdmissionConstraintsV1" or self.version != 1:
758
+ raise DriveGovernanceError(
759
+ "unsupported_schema", "charter admission constraints are unsupported",
760
+ )
761
+ for field_name in ("objective_allow_terms", "objective_deny_terms"):
762
+ values = tuple(getattr(self, field_name))
763
+ if len(values) > 30:
764
+ raise DriveGovernanceError(
765
+ "invalid_admission_constraints", f"{field_name} exceeds 30 items",
766
+ )
767
+ canonical = tuple(sorted({
768
+ _text(item, field_name, 80).casefold() for item in values
769
+ }))
770
+ if values != canonical:
771
+ raise DriveGovernanceError(
772
+ "invalid_admission_constraints",
773
+ f"{field_name} must be unique, sorted, and lowercase",
774
+ )
775
+ for field_name in ("capability_ceiling", "capability_deny"):
776
+ values = tuple(getattr(self, field_name))
777
+ if len(values) > 30:
778
+ raise DriveGovernanceError(
779
+ "invalid_admission_constraints", f"{field_name} exceeds 30 items",
780
+ )
781
+ canonical = tuple(sorted({
782
+ _identifier(item, field_name) for item in values
783
+ }))
784
+ if values != canonical:
785
+ raise DriveGovernanceError(
786
+ "invalid_admission_constraints",
787
+ f"{field_name} must be unique and sorted",
788
+ )
789
+ boundaries = _refs(
790
+ self.required_boundary_refs, required=False, maximum=30,
791
+ )
792
+ if boundaries != self.required_boundary_refs:
793
+ raise DriveGovernanceError(
794
+ "invalid_admission_constraints",
795
+ "required boundary references are not canonical",
796
+ )
797
+ shareability = tuple(self.allowed_shareability)
798
+ if (
799
+ not shareability
800
+ or len(shareability) > len(_SHAREABILITY)
801
+ or tuple(sorted(set(shareability))) != shareability
802
+ or any(item not in _SHAREABILITY for item in shareability)
803
+ ):
804
+ raise DriveGovernanceError(
805
+ "invalid_admission_constraints",
806
+ "allowed shareability lanes are invalid",
807
+ )
808
+ recipients = tuple(self.allowed_recipient_ids)
809
+ if len(recipients) > 30 or tuple(sorted(set(recipients))) != recipients:
810
+ raise DriveGovernanceError(
811
+ "invalid_admission_constraints", "recipient IDs are not canonical",
812
+ )
813
+ for recipient in recipients:
814
+ _identifier(recipient, "allowed_recipient_id", maximum=128)
815
+ if any(not isinstance(value, bool) for value in (
816
+ self.allow_destructive, self.allow_root_shell, self.allow_messaging,
817
+ )):
818
+ raise DriveGovernanceError(
819
+ "invalid_admission_constraints", "admission flags must be boolean",
820
+ )
821
+
822
+ def payload(self) -> Dict[str, Any]:
823
+ return {
824
+ "schema": self.schema,
825
+ "version": self.version,
826
+ "objective_allow_terms": list(self.objective_allow_terms),
827
+ "objective_deny_terms": list(self.objective_deny_terms),
828
+ "capability_ceiling": list(self.capability_ceiling),
829
+ "capability_deny": list(self.capability_deny),
830
+ "required_boundary_refs": list(self.required_boundary_refs),
831
+ "allowed_shareability": list(self.allowed_shareability),
832
+ "allowed_recipient_ids": list(self.allowed_recipient_ids),
833
+ "allow_destructive": self.allow_destructive,
834
+ "allow_root_shell": self.allow_root_shell,
835
+ "allow_messaging": self.allow_messaging,
836
+ }
837
+
838
+ @classmethod
839
+ def from_payload(
840
+ cls, payload: Mapping[str, Any],
841
+ ) -> "CharterAdmissionConstraintsV1":
842
+ return cls(
843
+ objective_allow_terms=tuple(payload.get("objective_allow_terms") or ()),
844
+ objective_deny_terms=tuple(payload.get("objective_deny_terms") or ()),
845
+ capability_ceiling=tuple(payload.get("capability_ceiling") or ()),
846
+ capability_deny=tuple(payload.get("capability_deny") or ()),
847
+ required_boundary_refs=tuple(
848
+ payload.get("required_boundary_refs") or ()),
849
+ allowed_shareability=tuple(payload.get("allowed_shareability") or ()),
850
+ allowed_recipient_ids=tuple(
851
+ payload.get("allowed_recipient_ids") or ()),
852
+ allow_destructive=payload.get("allow_destructive") is True,
853
+ allow_root_shell=payload.get("allow_root_shell") is True,
854
+ allow_messaging=payload.get("allow_messaging") is True,
855
+ schema=str(payload.get("schema") or ""),
856
+ version=int(payload.get("version") or 0),
857
+ )
858
+
859
+
860
+ @dataclass(frozen=True)
861
+ class CharterRevisionV1:
862
+ revision_id: str
863
+ content_digest: str
864
+ charter_key: str
865
+ revision_label: str
866
+ parent_revision_id: Optional[str]
867
+ title: str
868
+ purpose_summary: str
869
+ principles: tuple[str, ...]
870
+ drive_weights: tuple[tuple[str, float], ...]
871
+ ranking_budget: RankingBudgetV1
872
+ scope: ScopeV1
873
+ evidence_refs: tuple[str, ...]
874
+ proposed_by: str
875
+ proposed_at: str
876
+ expires_at: str
877
+ admission_constraints: Optional[CharterAdmissionConstraintsV1] = None
878
+ schema: str = "CharterRevisionV1"
879
+ version: int = 1
880
+
881
+ @classmethod
882
+ def create(
883
+ cls,
884
+ *,
885
+ charter_key: str,
886
+ revision_label: str,
887
+ parent_revision_id: Optional[str],
888
+ title: str,
889
+ purpose_summary: str,
890
+ principles: Iterable[str],
891
+ drive_weights: Mapping[str, float],
892
+ ranking_budget: RankingBudgetV1,
893
+ scope: ScopeV1,
894
+ evidence_refs: Iterable[str],
895
+ proposed_by: str,
896
+ proposed_at: datetime,
897
+ expires_at: datetime,
898
+ admission_constraints: Optional[CharterAdmissionConstraintsV1] = None,
899
+ ) -> "CharterRevisionV1":
900
+ key = str(charter_key or "").strip().lower()
901
+ if not _SAFE_KEY.fullmatch(key):
902
+ raise DriveGovernanceError(
903
+ "invalid_charter_key", "charter key is invalid",
904
+ )
905
+ label = _identifier(revision_label, "revision_label", maximum=64)
906
+ parent = (
907
+ _identifier(parent_revision_id, "parent_revision_id")
908
+ if parent_revision_id else None
909
+ )
910
+ normalized_principles = tuple(
911
+ _text(item, "principle", 300) for item in principles or ()
912
+ )
913
+ if not normalized_principles or len(normalized_principles) > 20:
914
+ raise DriveGovernanceError(
915
+ "invalid_principles", "charter requires 1 to 20 principles",
916
+ )
917
+ if len(set(normalized_principles)) != len(normalized_principles):
918
+ raise DriveGovernanceError(
919
+ "invalid_principles", "charter principles must be unique",
920
+ )
921
+ weights: list[tuple[str, float]] = []
922
+ for raw_drive_id, raw_weight in (drive_weights or {}).items():
923
+ drive_id = _identifier(raw_drive_id, "drive_id")
924
+ weight = _bounded_float(
925
+ raw_weight, f"drive weight {drive_id}", minimum=0.000001,
926
+ maximum=1.0,
927
+ )
928
+ weights.append((drive_id, weight))
929
+ weights.sort()
930
+ if not weights or len(weights) > 20:
931
+ raise DriveGovernanceError(
932
+ "invalid_drive_weights", "charter requires 1 to 20 drive weights",
933
+ )
934
+ if sum(weight for _, weight in weights) > 1.00000001:
935
+ raise DriveGovernanceError(
936
+ "drive_budget_exceeded", "drive weights must sum to at most 1.0",
937
+ )
938
+ proposed = _as_utc(proposed_at)
939
+ expiry = _as_utc(expires_at)
940
+ if expiry - proposed < timedelta(hours=1):
941
+ raise DriveGovernanceError(
942
+ "invalid_expiry", "charter lifetime must be at least one hour",
943
+ )
944
+ if expiry - proposed > timedelta(days=366):
945
+ raise DriveGovernanceError(
946
+ "invalid_expiry", "charter lifetime cannot exceed 366 days",
947
+ )
948
+ constraints = admission_constraints or CharterAdmissionConstraintsV1()
949
+ authority = {
950
+ "schema": "CharterRevisionV1", "version": 1,
951
+ "charter_key": key,
952
+ "revision_label": label,
953
+ "parent_revision_id": parent,
954
+ "title": _text(title, "title", 120),
955
+ "purpose_summary": _text(
956
+ purpose_summary, "purpose_summary", 600,
957
+ ),
958
+ "principles": list(normalized_principles),
959
+ "drive_weights": [[drive_id, weight] for drive_id, weight in weights],
960
+ "ranking_budget": ranking_budget.payload(),
961
+ "scope": scope.payload(),
962
+ "evidence_refs": list(_refs(
963
+ evidence_refs, required=True, maximum=30,
964
+ )),
965
+ "proposed_by": _identifier(
966
+ proposed_by, "proposed_by", maximum=128,
967
+ ),
968
+ "proposed_at": _iso(proposed),
969
+ "expires_at": _iso(expiry),
970
+ "admission_constraints": constraints.payload(),
971
+ }
972
+ digest = _digest(authority)
973
+ return cls(
974
+ revision_id=f"charter:{key}:{digest[:24]}",
975
+ content_digest=digest,
976
+ charter_key=key,
977
+ revision_label=label,
978
+ parent_revision_id=parent,
979
+ title=authority["title"],
980
+ purpose_summary=authority["purpose_summary"],
981
+ principles=normalized_principles,
982
+ drive_weights=tuple(weights),
983
+ ranking_budget=ranking_budget,
984
+ scope=scope,
985
+ evidence_refs=tuple(authority["evidence_refs"]),
986
+ proposed_by=authority["proposed_by"],
987
+ proposed_at=authority["proposed_at"],
988
+ expires_at=authority["expires_at"],
989
+ admission_constraints=constraints,
990
+ )
991
+
992
+ def authority_payload(self) -> Dict[str, Any]:
993
+ payload = {
994
+ "schema": self.schema, "version": self.version,
995
+ "charter_key": self.charter_key,
996
+ "revision_label": self.revision_label,
997
+ "parent_revision_id": self.parent_revision_id,
998
+ "title": self.title,
999
+ "purpose_summary": self.purpose_summary,
1000
+ "principles": list(self.principles),
1001
+ "drive_weights": [list(item) for item in self.drive_weights],
1002
+ "ranking_budget": self.ranking_budget.payload(),
1003
+ "scope": self.scope.payload(),
1004
+ "evidence_refs": list(self.evidence_refs),
1005
+ "proposed_by": self.proposed_by,
1006
+ "proposed_at": self.proposed_at,
1007
+ "expires_at": self.expires_at,
1008
+ }
1009
+ if self.admission_constraints is not None:
1010
+ payload["admission_constraints"] = self.admission_constraints.payload()
1011
+ return payload
1012
+
1013
+ def payload(self) -> Dict[str, Any]:
1014
+ return {
1015
+ **self.authority_payload(),
1016
+ "revision_id": self.revision_id,
1017
+ "content_digest": self.content_digest,
1018
+ }
1019
+
1020
+ def validate_integrity(self) -> None:
1021
+ if self.schema != "CharterRevisionV1" or self.version != 1:
1022
+ raise DriveGovernanceError(
1023
+ "unsupported_schema", "charter revision schema is unsupported",
1024
+ )
1025
+ if not _SAFE_KEY.fullmatch(str(self.charter_key or "")):
1026
+ raise DriveGovernanceError(
1027
+ "invalid_charter_key", "charter key is invalid",
1028
+ )
1029
+ _identifier(self.revision_label, "revision_label", maximum=64)
1030
+ if self.parent_revision_id:
1031
+ _identifier(self.parent_revision_id, "parent_revision_id")
1032
+ if _text(self.title, "title", 120) != self.title or _text(
1033
+ self.purpose_summary, "purpose_summary", 600,
1034
+ ) != self.purpose_summary:
1035
+ raise DriveGovernanceError(
1036
+ "invalid_text", "charter text is not normalized and bounded",
1037
+ )
1038
+ if not 1 <= len(self.principles) <= 20 or len(
1039
+ set(self.principles)
1040
+ ) != len(self.principles):
1041
+ raise DriveGovernanceError(
1042
+ "invalid_principles", "charter principles are invalid",
1043
+ )
1044
+ if any(_text(item, "principle", 300) != item for item in self.principles):
1045
+ raise DriveGovernanceError(
1046
+ "invalid_principles", "charter principles are not canonical",
1047
+ )
1048
+ if not 1 <= len(self.drive_weights) <= 20:
1049
+ raise DriveGovernanceError(
1050
+ "invalid_drive_weights", "charter drive weights are invalid",
1051
+ )
1052
+ drive_ids = [item[0] for item in self.drive_weights]
1053
+ if drive_ids != sorted(drive_ids) or len(set(drive_ids)) != len(drive_ids):
1054
+ raise DriveGovernanceError(
1055
+ "invalid_drive_weights", "charter drive weights are not canonical",
1056
+ )
1057
+ for drive_id, weight in self.drive_weights:
1058
+ _identifier(drive_id, "drive_id")
1059
+ _bounded_float(
1060
+ weight, f"drive weight {drive_id}", minimum=0.000001, maximum=1.0,
1061
+ )
1062
+ if sum(weight for _, weight in self.drive_weights) > 1.00000001:
1063
+ raise DriveGovernanceError(
1064
+ "drive_budget_exceeded", "drive weights exceed the charter budget",
1065
+ )
1066
+ if _refs(
1067
+ self.evidence_refs, required=True, maximum=30,
1068
+ ) != self.evidence_refs:
1069
+ raise DriveGovernanceError(
1070
+ "invalid_evidence", "charter evidence references are not canonical",
1071
+ )
1072
+ if self.admission_constraints is not None:
1073
+ self.admission_constraints.__post_init__()
1074
+ _identifier(self.proposed_by, "proposed_by", maximum=128)
1075
+ proposed = _parse_time(self.proposed_at, field="charter proposed_at")
1076
+ expiry = _parse_time(self.expires_at, field="charter expires_at")
1077
+ if not timedelta(hours=1) <= expiry - proposed <= timedelta(days=366):
1078
+ raise DriveGovernanceError(
1079
+ "invalid_expiry", "charter expiry is outside its bounded lifetime",
1080
+ )
1081
+ digest = _digest(self.authority_payload())
1082
+ if digest != self.content_digest or self.revision_id != (
1083
+ f"charter:{self.charter_key}:{digest[:24]}"
1084
+ ):
1085
+ raise DriveGovernanceError(
1086
+ "immutable_object_tampered", "charter revision integrity mismatch",
1087
+ )
1088
+
1089
+ def weight_map(self) -> Dict[str, float]:
1090
+ return dict(self.drive_weights)
1091
+
1092
+ @classmethod
1093
+ def from_payload(cls, payload: Mapping[str, Any]) -> "CharterRevisionV1":
1094
+ result = cls(
1095
+ revision_id=str(payload["revision_id"]),
1096
+ content_digest=str(payload["content_digest"]),
1097
+ charter_key=str(payload["charter_key"]),
1098
+ revision_label=str(payload["revision_label"]),
1099
+ parent_revision_id=(
1100
+ str(payload["parent_revision_id"])
1101
+ if payload.get("parent_revision_id") else None
1102
+ ),
1103
+ title=str(payload["title"]),
1104
+ purpose_summary=str(payload["purpose_summary"]),
1105
+ principles=tuple(payload.get("principles") or ()),
1106
+ drive_weights=tuple(
1107
+ (str(item[0]), float(item[1]))
1108
+ for item in payload.get("drive_weights") or ()
1109
+ ),
1110
+ ranking_budget=RankingBudgetV1(**dict(payload["ranking_budget"])),
1111
+ scope=ScopeV1(**dict(payload["scope"])),
1112
+ evidence_refs=tuple(payload.get("evidence_refs") or ()),
1113
+ proposed_by=str(payload["proposed_by"]),
1114
+ proposed_at=str(payload["proposed_at"]),
1115
+ expires_at=str(payload["expires_at"]),
1116
+ admission_constraints=(
1117
+ CharterAdmissionConstraintsV1.from_payload(
1118
+ dict(payload["admission_constraints"]),
1119
+ )
1120
+ if payload.get("admission_constraints") else None
1121
+ ),
1122
+ )
1123
+ result.validate_integrity()
1124
+ return result
1125
+
1126
+
1127
+ @dataclass(frozen=True)
1128
+ class GoalRankInputV1:
1129
+ """Server-built projection of a P3-created project eligible for ordering."""
1130
+
1131
+ goal_id: str
1132
+ proposal_id: str
1133
+ goal_fingerprint: str
1134
+ title: str
1135
+ objective_summary: str
1136
+ rationale_summary: str
1137
+ evidence_refs: tuple[str, ...]
1138
+ policy_decision_refs: tuple[str, ...]
1139
+ scope: ScopeV1
1140
+ schema: str = "GoalRankInputV1"
1141
+ version: int = 1
1142
+
1143
+ def __post_init__(self) -> None:
1144
+ _identifier(self.goal_id, "goal_id")
1145
+ _identifier(self.proposal_id, "proposal_id")
1146
+ _identifier(self.goal_fingerprint, "goal_fingerprint")
1147
+ _text(self.title, "title", 160)
1148
+ _text(self.objective_summary, "objective_summary", 600)
1149
+ _text(self.rationale_summary, "rationale_summary", 500)
1150
+ _refs(self.evidence_refs, maximum=30)
1151
+ refs = _refs(
1152
+ self.policy_decision_refs,
1153
+ field="policy_decision_refs",
1154
+ maximum=20,
1155
+ )
1156
+ if len(refs) != len(self.policy_decision_refs):
1157
+ raise DriveGovernanceError(
1158
+ "duplicate_policy_reference", "policy decision references repeat",
1159
+ )
1160
+
1161
+ def payload(self) -> Dict[str, Any]:
1162
+ return {
1163
+ "schema": self.schema, "version": self.version,
1164
+ "goal_id": self.goal_id,
1165
+ "proposal_id": self.proposal_id,
1166
+ "goal_fingerprint": self.goal_fingerprint,
1167
+ "title": self.title,
1168
+ "objective_summary": self.objective_summary,
1169
+ "rationale_summary": self.rationale_summary,
1170
+ "evidence_refs": list(self.evidence_refs),
1171
+ "policy_decision_refs": list(self.policy_decision_refs),
1172
+ "scope": self.scope.payload(),
1173
+ }
1174
+
1175
+
1176
+ @dataclass(frozen=True)
1177
+ class DriveContributionV1:
1178
+ drive_id: str
1179
+ state: str
1180
+ weight: float
1181
+ raw_signal_value: float
1182
+ mean_confidence: float
1183
+ weighted_value: float
1184
+ abs_budget: float
1185
+ signal_refs: tuple[str, ...]
1186
+ evidence_refs: tuple[str, ...]
1187
+ rationale_summaries: tuple[str, ...]
1188
+ schema: str = "DriveContributionV1"
1189
+ version: int = 1
1190
+
1191
+ def payload(self) -> Dict[str, Any]:
1192
+ return {
1193
+ "schema": self.schema, "version": self.version,
1194
+ "drive_id": self.drive_id,
1195
+ "state": self.state,
1196
+ "weight": self.weight,
1197
+ "raw_signal_value": self.raw_signal_value,
1198
+ "mean_confidence": self.mean_confidence,
1199
+ "weighted_value": self.weighted_value,
1200
+ "abs_budget": self.abs_budget,
1201
+ "signal_refs": list(self.signal_refs),
1202
+ "evidence_refs": list(self.evidence_refs),
1203
+ "rationale_summaries": list(self.rationale_summaries),
1204
+ }
1205
+
1206
+
1207
+ @dataclass(frozen=True)
1208
+ class GoalRankResultV1:
1209
+ goal_id: str
1210
+ proposal_id: str
1211
+ state: str
1212
+ eligible: bool
1213
+ total_score: Optional[float]
1214
+ contributions: tuple[DriveContributionV1, ...]
1215
+ drive_states: Dict[str, str]
1216
+ evidence_refs: tuple[str, ...]
1217
+ policy_decision_refs: tuple[str, ...]
1218
+ rationale_summary: str
1219
+ scope: ScopeV1
1220
+ authorization_effect: str = "none"
1221
+ schema: str = "GoalRankResultV1"
1222
+ version: int = 1
1223
+
1224
+ def payload(self) -> Dict[str, Any]:
1225
+ return {
1226
+ "schema": self.schema, "version": self.version,
1227
+ "goal_id": self.goal_id,
1228
+ "proposal_id": self.proposal_id,
1229
+ "state": self.state,
1230
+ "eligible": self.eligible,
1231
+ "total_score": self.total_score,
1232
+ "contributions": [item.payload() for item in self.contributions],
1233
+ "drive_states": dict(sorted(self.drive_states.items())),
1234
+ "evidence_refs": list(self.evidence_refs),
1235
+ "policy_decision_refs": list(self.policy_decision_refs),
1236
+ "rationale_summary": self.rationale_summary,
1237
+ "scope": self.scope.payload(),
1238
+ "authorization_effect": self.authorization_effect,
1239
+ "required_p3_stages": list(_REQUIRED_P3_STAGES),
1240
+ }
1241
+
1242
+
1243
+ @dataclass(frozen=True)
1244
+ class RankingBatchV1:
1245
+ status: str
1246
+ mode: str
1247
+ ranking_applied: bool
1248
+ charter_revision_id: Optional[str]
1249
+ input_order: tuple[str, ...]
1250
+ suggested_order: tuple[str, ...]
1251
+ effective_order: tuple[str, ...]
1252
+ held_goal_ids: tuple[str, ...]
1253
+ results: tuple[GoalRankResultV1, ...]
1254
+ generated_at: str
1255
+ authorization_effect: str = "none"
1256
+ schema: str = "GoalRankingBatchV1"
1257
+ version: int = 1
1258
+
1259
+ def payload(self) -> Dict[str, Any]:
1260
+ return {
1261
+ "schema": self.schema, "version": self.version,
1262
+ "status": self.status,
1263
+ "mode": self.mode,
1264
+ "ranking_applied": self.ranking_applied,
1265
+ "charter_revision_id": self.charter_revision_id,
1266
+ "input_order": list(self.input_order),
1267
+ "suggested_order": list(self.suggested_order),
1268
+ "effective_order": list(self.effective_order),
1269
+ "held_goal_ids": list(self.held_goal_ids),
1270
+ "results": [item.payload() for item in self.results],
1271
+ "generated_at": self.generated_at,
1272
+ "authorization_effect": self.authorization_effect,
1273
+ }
1274
+
1275
+ def observer_projection(
1276
+ self,
1277
+ *,
1278
+ viewer_person_id: str,
1279
+ owner_person_id: str,
1280
+ audiences: set[str] | frozenset[str] = frozenset(),
1281
+ ) -> Dict[str, Any]:
1282
+ visible = tuple(
1283
+ item for item in self.results
1284
+ if item.scope.visible_to(
1285
+ viewer_person_id=viewer_person_id,
1286
+ owner_person_id=owner_person_id,
1287
+ audiences=audiences,
1288
+ )
1289
+ )
1290
+ ids = {item.goal_id for item in visible}
1291
+ payload = self.payload()
1292
+ payload["results"] = [item.payload() for item in visible]
1293
+ for key in ("input_order", "suggested_order", "effective_order"):
1294
+ payload[key] = [goal_id for goal_id in payload[key] if goal_id in ids]
1295
+ payload["held_goal_ids"] = [
1296
+ goal_id for goal_id in payload["held_goal_ids"] if goal_id in ids
1297
+ ]
1298
+ return payload
1299
+
1300
+
1301
+ def charter_transition_binding(
1302
+ revision: CharterRevisionV1,
1303
+ *,
1304
+ transition: str,
1305
+ expected_active_revision_id: Optional[str],
1306
+ ) -> ActionBinding:
1307
+ """Build one exact, privacy-bounded ApprovalAuthority action binding."""
1308
+
1309
+ normalized = str(transition or "").strip().lower()
1310
+ if normalized not in _TRANSITIONS:
1311
+ raise DriveGovernanceError(
1312
+ "invalid_transition", "transition must be activate or revoke",
1313
+ )
1314
+ revision.validate_integrity()
1315
+ constraints = {
1316
+ "charter_key_digest": _digest(revision.charter_key),
1317
+ "revision_id_digest": _digest(revision.revision_id),
1318
+ "content_digest": revision.content_digest,
1319
+ "expected_active_revision_digest": _digest(
1320
+ expected_active_revision_id,
1321
+ ),
1322
+ }
1323
+ scope = {
1324
+ "version": 1,
1325
+ "job_type": "charter_governance",
1326
+ "action_name": f"charter_revision_{normalized}",
1327
+ "risk": "authority_mutation",
1328
+ "constraints": constraints,
1329
+ }
1330
+ snapshot = {
1331
+ "version": 1,
1332
+ "transition": normalized,
1333
+ "revision_id": revision.revision_id,
1334
+ "content_digest": revision.content_digest,
1335
+ "expected_active_revision_id": expected_active_revision_id,
1336
+ "scope": scope,
1337
+ }
1338
+ return ActionBinding(
1339
+ action_digest=_digest(snapshot),
1340
+ scope=scope,
1341
+ scope_digest=_digest(scope),
1342
+ )
1343
+
1344
+
1345
+ def charter_transition_subject(
1346
+ revision: CharterRevisionV1,
1347
+ *,
1348
+ transition: str,
1349
+ ) -> ApprovalSubjectBinding:
1350
+ normalized = str(transition or "").strip().lower()
1351
+ if normalized not in _TRANSITIONS:
1352
+ raise DriveGovernanceError(
1353
+ "invalid_transition", "transition must be activate or revoke",
1354
+ )
1355
+ revision.validate_integrity()
1356
+ return ApprovalSubjectBinding(
1357
+ kind="charter_transition",
1358
+ subject_id=revision.revision_id,
1359
+ revision=revision.content_digest,
1360
+ action=normalized,
1361
+ )
1362
+
1363
+
1364
+ def charter_transition_presentation(
1365
+ revision: CharterRevisionV1,
1366
+ *,
1367
+ transition: str,
1368
+ binding: ActionBinding,
1369
+ ) -> Dict[str, Any]:
1370
+ """Build the bounded owner view without charter principles or evidence."""
1371
+
1372
+ normalized = str(transition or "").strip().lower()
1373
+ if normalized not in _TRANSITIONS:
1374
+ raise DriveGovernanceError(
1375
+ "invalid_transition", "transition must be activate or revoke",
1376
+ )
1377
+ verb = "Activate" if normalized == "activate" else "Revoke"
1378
+ return {
1379
+ "schema": PRESENTATION_SCHEMA,
1380
+ "version": 1,
1381
+ "summary": (
1382
+ f"{verb} charter {revision.title} "
1383
+ f"({revision.revision_label})"
1384
+ ),
1385
+ "action_name": f"charter_revision_{normalized}",
1386
+ "risk": "authority_mutation",
1387
+ "effect": "mutation",
1388
+ "target": f"charter:{revision.charter_key}",
1389
+ "capabilities": [],
1390
+ "deadline": "bounded by approval request expiry",
1391
+ "reversibility": (
1392
+ "revocable by a new exact owner decision"
1393
+ if normalized == "activate"
1394
+ else "requires a new charter activation decision"
1395
+ ),
1396
+ "constraints": dict(binding.scope["constraints"]),
1397
+ }
1398
+
1399
+
1400
+ class DriveGovernanceStore:
1401
+ """Append-only SQLite ledger for drives, signals, and charter lifecycle."""
1402
+
1403
+ def __init__(self, db_path: str | os.PathLike[str]) -> None:
1404
+ self.path = Path(db_path)
1405
+ self.path.parent.mkdir(parents=True, exist_ok=True)
1406
+ if not self.path.exists():
1407
+ self.path.touch(mode=0o600)
1408
+ else:
1409
+ os.chmod(self.path, 0o600)
1410
+ self._lock = threading.RLock()
1411
+ self._conn = sqlite3.connect(str(self.path), check_same_thread=False)
1412
+ self._conn.row_factory = sqlite3.Row
1413
+ self._conn.execute("PRAGMA foreign_keys=ON")
1414
+ self._conn.execute("PRAGMA busy_timeout=30000")
1415
+ self._closed = False
1416
+ self._initialize()
1417
+
1418
+ def close(self) -> None:
1419
+ """Release the feature-owned SQLite handle; exact retries are safe."""
1420
+
1421
+ with self._lock:
1422
+ if self._closed:
1423
+ return
1424
+ self._conn.close()
1425
+ self._closed = True
1426
+
1427
+ def _initialize(self) -> None:
1428
+ with self._lock, self._conn:
1429
+ self._conn.execute("PRAGMA journal_mode=WAL")
1430
+ self._conn.executescript(
1431
+ """
1432
+ CREATE TABLE IF NOT EXISTS governance_operations (
1433
+ operation_id TEXT PRIMARY KEY,
1434
+ object_kind TEXT NOT NULL,
1435
+ object_id TEXT NOT NULL,
1436
+ content_digest TEXT NOT NULL,
1437
+ created_at TEXT NOT NULL
1438
+ );
1439
+
1440
+ CREATE TABLE IF NOT EXISTS drive_definitions (
1441
+ drive_id TEXT PRIMARY KEY,
1442
+ definition_digest TEXT NOT NULL,
1443
+ payload_json TEXT NOT NULL,
1444
+ created_at TEXT NOT NULL
1445
+ );
1446
+
1447
+ CREATE TABLE IF NOT EXISTS drive_signals (
1448
+ signal_seq INTEGER PRIMARY KEY AUTOINCREMENT,
1449
+ signal_id TEXT NOT NULL UNIQUE,
1450
+ signal_digest TEXT NOT NULL,
1451
+ drive_id TEXT NOT NULL,
1452
+ goal_fingerprint TEXT NOT NULL,
1453
+ state TEXT NOT NULL,
1454
+ observed_at TEXT NOT NULL,
1455
+ expires_at TEXT NOT NULL,
1456
+ payload_json TEXT NOT NULL,
1457
+ recorded_at TEXT NOT NULL,
1458
+ FOREIGN KEY(drive_id) REFERENCES drive_definitions(drive_id)
1459
+ );
1460
+ CREATE INDEX IF NOT EXISTS drive_signals_goal_idx
1461
+ ON drive_signals(goal_fingerprint, observed_at DESC, signal_seq);
1462
+ CREATE INDEX IF NOT EXISTS drive_signals_drive_idx
1463
+ ON drive_signals(drive_id, expires_at);
1464
+
1465
+ CREATE TABLE IF NOT EXISTS charter_revisions (
1466
+ revision_id TEXT PRIMARY KEY,
1467
+ charter_key TEXT NOT NULL,
1468
+ content_digest TEXT NOT NULL,
1469
+ parent_revision_id TEXT,
1470
+ proposed_at TEXT NOT NULL,
1471
+ expires_at TEXT NOT NULL,
1472
+ payload_json TEXT NOT NULL
1473
+ );
1474
+ CREATE INDEX IF NOT EXISTS charter_revisions_key_idx
1475
+ ON charter_revisions(charter_key, proposed_at DESC);
1476
+
1477
+ CREATE TABLE IF NOT EXISTS charter_lifecycle_events (
1478
+ event_seq INTEGER PRIMARY KEY AUTOINCREMENT,
1479
+ event_id TEXT NOT NULL UNIQUE,
1480
+ charter_key TEXT NOT NULL,
1481
+ revision_id TEXT NOT NULL,
1482
+ transition TEXT NOT NULL,
1483
+ from_revision_id TEXT,
1484
+ action_digest TEXT NOT NULL,
1485
+ approval_request_id TEXT NOT NULL,
1486
+ decision_id TEXT NOT NULL,
1487
+ principal_id TEXT NOT NULL,
1488
+ authority_evidence TEXT NOT NULL,
1489
+ occurred_at TEXT NOT NULL,
1490
+ payload_json TEXT NOT NULL,
1491
+ FOREIGN KEY(revision_id) REFERENCES charter_revisions(revision_id)
1492
+ );
1493
+ CREATE INDEX IF NOT EXISTS charter_events_key_idx
1494
+ ON charter_lifecycle_events(charter_key, event_seq);
1495
+ CREATE INDEX IF NOT EXISTS charter_events_revision_idx
1496
+ ON charter_lifecycle_events(revision_id, event_seq);
1497
+
1498
+ CREATE TABLE IF NOT EXISTS charter_transition_operations (
1499
+ operation_id TEXT PRIMARY KEY,
1500
+ transition_digest TEXT NOT NULL,
1501
+ revision_id TEXT NOT NULL,
1502
+ transition TEXT NOT NULL,
1503
+ approval_request_id TEXT NOT NULL,
1504
+ event_id TEXT NOT NULL,
1505
+ created_at TEXT NOT NULL
1506
+ );
1507
+
1508
+ CREATE TABLE IF NOT EXISTS charter_authority_uses (
1509
+ approval_request_id TEXT PRIMARY KEY,
1510
+ action_digest TEXT NOT NULL,
1511
+ operation_id TEXT NOT NULL UNIQUE,
1512
+ event_id TEXT NOT NULL,
1513
+ used_at TEXT NOT NULL
1514
+ );
1515
+ """
1516
+ )
1517
+ current = int(self._conn.execute("PRAGMA user_version").fetchone()[0])
1518
+ if current < DRIVE_GOVERNANCE_SCHEMA_VERSION:
1519
+ self._conn.execute(
1520
+ f"PRAGMA user_version={DRIVE_GOVERNANCE_SCHEMA_VERSION}"
1521
+ )
1522
+ os.chmod(self.path, 0o600)
1523
+
1524
+ def _operation(
1525
+ self,
1526
+ conn: sqlite3.Connection,
1527
+ *,
1528
+ operation_id: str,
1529
+ object_kind: str,
1530
+ object_id: str,
1531
+ content_digest: str,
1532
+ now: datetime,
1533
+ ) -> bool:
1534
+ operation = _operation_id(operation_id)
1535
+ row = conn.execute(
1536
+ "SELECT * FROM governance_operations WHERE operation_id=?",
1537
+ (operation,),
1538
+ ).fetchone()
1539
+ if row is not None:
1540
+ if (
1541
+ row["object_kind"] != object_kind
1542
+ or row["object_id"] != object_id
1543
+ or row["content_digest"] != content_digest
1544
+ ):
1545
+ raise DriveGovernanceError(
1546
+ "operation_replay_conflict",
1547
+ "operation replay does not match its immutable first use",
1548
+ )
1549
+ return True
1550
+ conn.execute(
1551
+ "INSERT INTO governance_operations "
1552
+ "(operation_id,object_kind,object_id,content_digest,created_at) "
1553
+ "VALUES (?,?,?,?,?)",
1554
+ (operation, object_kind, object_id, content_digest, _iso(now)),
1555
+ )
1556
+ return False
1557
+
1558
+ def register_drive(
1559
+ self,
1560
+ drive: DriveV1,
1561
+ *,
1562
+ operation_id: str,
1563
+ now: Optional[datetime] = None,
1564
+ ) -> Dict[str, Any]:
1565
+ observed = _as_utc(now)
1566
+ actual_digest = _digest(drive.authority_payload())
1567
+ with self._lock, self._conn:
1568
+ self._conn.execute("BEGIN IMMEDIATE")
1569
+ replayed = self._operation(
1570
+ self._conn,
1571
+ operation_id=operation_id,
1572
+ object_kind="drive",
1573
+ object_id=drive.drive_id,
1574
+ content_digest=actual_digest,
1575
+ now=observed,
1576
+ )
1577
+ if replayed:
1578
+ existing = self._conn.execute(
1579
+ "SELECT definition_digest,payload_json FROM drive_definitions "
1580
+ "WHERE drive_id=?", (drive.drive_id,),
1581
+ ).fetchone()
1582
+ if existing is None or existing["definition_digest"] != actual_digest:
1583
+ raise DriveGovernanceError(
1584
+ "ledger_integrity_error", "replayed drive is missing or changed",
1585
+ )
1586
+ return {
1587
+ "enabled": True, "status": "drive_replayed",
1588
+ "drive_id": drive.drive_id, "replayed": True,
1589
+ }
1590
+ drive.validate_integrity()
1591
+ encoded = _canonical(drive.payload())
1592
+ existing = self._conn.execute(
1593
+ "SELECT * FROM drive_definitions WHERE drive_id=?",
1594
+ (drive.drive_id,),
1595
+ ).fetchone()
1596
+ if existing is not None:
1597
+ if (
1598
+ existing["definition_digest"] != drive.definition_digest
1599
+ or existing["payload_json"] != encoded
1600
+ ):
1601
+ raise DriveGovernanceError(
1602
+ "immutable_drive_conflict", "drive definition is immutable",
1603
+ )
1604
+ status = "drive_replayed"
1605
+ else:
1606
+ self._conn.execute(
1607
+ "INSERT INTO drive_definitions "
1608
+ "(drive_id,definition_digest,payload_json,created_at) "
1609
+ "VALUES (?,?,?,?)",
1610
+ (
1611
+ drive.drive_id, drive.definition_digest, encoded,
1612
+ _iso(observed),
1613
+ ),
1614
+ )
1615
+ status = "drive_registered"
1616
+ return {
1617
+ "enabled": True, "status": status,
1618
+ "drive_id": drive.drive_id,
1619
+ "replayed": status == "drive_replayed",
1620
+ }
1621
+
1622
+ def get_drive(self, drive_id: str) -> Optional[DriveV1]:
1623
+ with self._lock:
1624
+ row = self._conn.execute(
1625
+ "SELECT payload_json FROM drive_definitions WHERE drive_id=?",
1626
+ (str(drive_id),),
1627
+ ).fetchone()
1628
+ return DriveV1.from_payload(json.loads(row["payload_json"])) if row else None
1629
+
1630
+ def list_drives(self) -> list[DriveV1]:
1631
+ with self._lock:
1632
+ rows = self._conn.execute(
1633
+ "SELECT payload_json FROM drive_definitions ORDER BY created_at,drive_id"
1634
+ ).fetchall()
1635
+ return [DriveV1.from_payload(json.loads(row["payload_json"])) for row in rows]
1636
+
1637
+ def record_signal(
1638
+ self,
1639
+ signal: DriveSignalV1,
1640
+ *,
1641
+ operation_id: str,
1642
+ now: Optional[datetime] = None,
1643
+ ) -> Dict[str, Any]:
1644
+ observed = _as_utc(now)
1645
+ actual_digest = _digest(signal.authority_payload())
1646
+ with self._lock, self._conn:
1647
+ self._conn.execute("BEGIN IMMEDIATE")
1648
+ replayed = self._operation(
1649
+ self._conn,
1650
+ operation_id=operation_id,
1651
+ object_kind="signal",
1652
+ object_id=signal.signal_id,
1653
+ content_digest=actual_digest,
1654
+ now=observed,
1655
+ )
1656
+ if replayed:
1657
+ existing = self._conn.execute(
1658
+ "SELECT signal_digest FROM drive_signals WHERE signal_id=?",
1659
+ (signal.signal_id,),
1660
+ ).fetchone()
1661
+ if existing is None or existing["signal_digest"] != actual_digest:
1662
+ raise DriveGovernanceError(
1663
+ "ledger_integrity_error", "replayed signal is missing or changed",
1664
+ )
1665
+ return {
1666
+ "enabled": True, "status": "signal_replayed",
1667
+ "signal_id": signal.signal_id, "replayed": True,
1668
+ }
1669
+ signal.validate_integrity()
1670
+ drive = self.get_drive(signal.drive_id)
1671
+ if drive is None:
1672
+ raise DriveGovernanceError("drive_unknown", "signal drive is unknown")
1673
+ if not drive.scope.permits_child(signal.scope):
1674
+ raise DriveGovernanceError(
1675
+ "scope_broadening", "signal scope broadens its registered drive",
1676
+ )
1677
+ encoded = _canonical(signal.payload())
1678
+ existing = self._conn.execute(
1679
+ "SELECT * FROM drive_signals WHERE signal_id=?",
1680
+ (signal.signal_id,),
1681
+ ).fetchone()
1682
+ if existing is not None:
1683
+ if (
1684
+ existing["signal_digest"] != signal.signal_digest
1685
+ or existing["payload_json"] != encoded
1686
+ ):
1687
+ raise DriveGovernanceError(
1688
+ "immutable_signal_conflict", "drive signal is immutable",
1689
+ )
1690
+ status = "signal_replayed"
1691
+ else:
1692
+ self._conn.execute(
1693
+ "INSERT INTO drive_signals "
1694
+ "(signal_id,signal_digest,drive_id,goal_fingerprint,state,"
1695
+ "observed_at,expires_at,payload_json,recorded_at) "
1696
+ "VALUES (?,?,?,?,?,?,?,?,?)",
1697
+ (
1698
+ signal.signal_id, signal.signal_digest, signal.drive_id,
1699
+ signal.goal_fingerprint, signal.state, signal.observed_at,
1700
+ signal.expires_at, encoded, _iso(observed),
1701
+ ),
1702
+ )
1703
+ status = "signal_recorded"
1704
+ return {
1705
+ "enabled": True, "status": status,
1706
+ "signal_id": signal.signal_id,
1707
+ "replayed": status == "signal_replayed",
1708
+ }
1709
+
1710
+ def signals_for_goal(
1711
+ self,
1712
+ goal_fingerprint: str,
1713
+ *,
1714
+ now: Optional[datetime] = None,
1715
+ include_expired: bool = False,
1716
+ ) -> list[DriveSignalV1]:
1717
+ with self._lock:
1718
+ rows = self._conn.execute(
1719
+ "SELECT payload_json FROM drive_signals "
1720
+ "WHERE goal_fingerprint=? "
1721
+ "ORDER BY observed_at DESC,signal_seq ASC",
1722
+ (str(goal_fingerprint),),
1723
+ ).fetchall()
1724
+ signals = [
1725
+ DriveSignalV1.from_payload(json.loads(row["payload_json"]))
1726
+ for row in rows
1727
+ ]
1728
+ if include_expired:
1729
+ return signals
1730
+ return [item for item in signals if item.state_at(now) != "expired"]
1731
+
1732
+ def propose_revision(
1733
+ self,
1734
+ revision: CharterRevisionV1,
1735
+ *,
1736
+ operation_id: str,
1737
+ now: Optional[datetime] = None,
1738
+ ) -> Dict[str, Any]:
1739
+ observed = _as_utc(now)
1740
+ actual_digest = _digest(revision.authority_payload())
1741
+ with self._lock, self._conn:
1742
+ self._conn.execute("BEGIN IMMEDIATE")
1743
+ replayed = self._operation(
1744
+ self._conn,
1745
+ operation_id=operation_id,
1746
+ object_kind="charter_revision",
1747
+ object_id=revision.revision_id,
1748
+ content_digest=actual_digest,
1749
+ now=observed,
1750
+ )
1751
+ if replayed:
1752
+ existing = self._conn.execute(
1753
+ "SELECT content_digest FROM charter_revisions WHERE revision_id=?",
1754
+ (revision.revision_id,),
1755
+ ).fetchone()
1756
+ if existing is None or existing["content_digest"] != actual_digest:
1757
+ raise DriveGovernanceError(
1758
+ "ledger_integrity_error",
1759
+ "replayed charter revision is missing or changed",
1760
+ )
1761
+ projection = self._revision_projection_conn(
1762
+ self._conn, revision.revision_id, observed,
1763
+ )
1764
+ projection.update({"enabled": True, "replayed": True})
1765
+ return projection
1766
+ revision.validate_integrity()
1767
+ if revision.parent_revision_id == revision.revision_id:
1768
+ raise DriveGovernanceError(
1769
+ "invalid_parent", "charter cannot be its own parent",
1770
+ )
1771
+ encoded = _canonical(revision.payload())
1772
+ existing = self._conn.execute(
1773
+ "SELECT * FROM charter_revisions WHERE revision_id=?",
1774
+ (revision.revision_id,),
1775
+ ).fetchone()
1776
+ if existing is not None:
1777
+ if (
1778
+ existing["content_digest"] != revision.content_digest
1779
+ or existing["payload_json"] != encoded
1780
+ ):
1781
+ raise DriveGovernanceError(
1782
+ "immutable_revision_conflict",
1783
+ "charter revision is immutable",
1784
+ )
1785
+ else:
1786
+ self._conn.execute(
1787
+ "INSERT INTO charter_revisions "
1788
+ "(revision_id,charter_key,content_digest,parent_revision_id,"
1789
+ "proposed_at,expires_at,payload_json) VALUES (?,?,?,?,?,?,?)",
1790
+ (
1791
+ revision.revision_id, revision.charter_key,
1792
+ revision.content_digest, revision.parent_revision_id,
1793
+ revision.proposed_at, revision.expires_at, encoded,
1794
+ ),
1795
+ )
1796
+ projection = self._revision_projection_conn(
1797
+ self._conn, revision.revision_id, observed,
1798
+ )
1799
+ projection.update({"enabled": True, "replayed": existing is not None})
1800
+ return projection
1801
+
1802
+ def get_revision(self, revision_id: str) -> Optional[CharterRevisionV1]:
1803
+ with self._lock:
1804
+ row = self._conn.execute(
1805
+ "SELECT payload_json FROM charter_revisions WHERE revision_id=?",
1806
+ (str(revision_id),),
1807
+ ).fetchone()
1808
+ return (
1809
+ CharterRevisionV1.from_payload(json.loads(row["payload_json"]))
1810
+ if row else None
1811
+ )
1812
+
1813
+ def _revision_projection_conn(
1814
+ self,
1815
+ conn: sqlite3.Connection,
1816
+ revision_id: str,
1817
+ now: datetime,
1818
+ ) -> Dict[str, Any]:
1819
+ row = conn.execute(
1820
+ "SELECT payload_json FROM charter_revisions WHERE revision_id=?",
1821
+ (revision_id,),
1822
+ ).fetchone()
1823
+ if row is None:
1824
+ raise DriveGovernanceError(
1825
+ "revision_unknown", "charter revision is unknown",
1826
+ )
1827
+ revision = CharterRevisionV1.from_payload(json.loads(row["payload_json"]))
1828
+ events = conn.execute(
1829
+ "SELECT * FROM charter_lifecycle_events "
1830
+ "WHERE revision_id=? ORDER BY event_seq",
1831
+ (revision_id,),
1832
+ ).fetchall()
1833
+ for event in events:
1834
+ self._validate_lifecycle_event(event)
1835
+ transitions = [event["transition"] for event in events]
1836
+ if "revoke" in transitions:
1837
+ status = "revoked"
1838
+ elif "supersede" in transitions:
1839
+ status = "superseded"
1840
+ elif "activate" in transitions:
1841
+ status = (
1842
+ "expired"
1843
+ if _parse_time(revision.expires_at, field="revision expires_at") <= now
1844
+ else "active"
1845
+ )
1846
+ else:
1847
+ status = (
1848
+ "expired"
1849
+ if _parse_time(revision.expires_at, field="revision expires_at") <= now
1850
+ else "proposed"
1851
+ )
1852
+ result = revision.payload()
1853
+ result["lifecycle_status"] = status
1854
+ result["lifecycle_event_refs"] = [event["event_id"] for event in events]
1855
+ return result
1856
+
1857
+ @staticmethod
1858
+ def _validate_lifecycle_event(row: Mapping[str, Any]) -> Dict[str, Any]:
1859
+ try:
1860
+ payload = json.loads(str(row["payload_json"]))
1861
+ except (KeyError, TypeError, ValueError, json.JSONDecodeError) as exc:
1862
+ raise DriveGovernanceError(
1863
+ "lifecycle_integrity_error", "lifecycle event payload is invalid",
1864
+ ) from exc
1865
+ fields = (
1866
+ "charter_key", "revision_id", "transition", "from_revision_id",
1867
+ "action_digest", "approval_request_id", "decision_id",
1868
+ "principal_id", "authority_evidence", "occurred_at",
1869
+ )
1870
+ if any(payload.get(field) != row[field] for field in fields):
1871
+ raise DriveGovernanceError(
1872
+ "lifecycle_integrity_error",
1873
+ "lifecycle event columns do not match immutable payload",
1874
+ )
1875
+ if row["event_id"] != f"charter-event:{_digest(payload)[:24]}":
1876
+ raise DriveGovernanceError(
1877
+ "lifecycle_integrity_error", "lifecycle event digest mismatch",
1878
+ )
1879
+ return payload
1880
+
1881
+ def revision_projection(
1882
+ self, revision_id: str, *, now: Optional[datetime] = None,
1883
+ ) -> Dict[str, Any]:
1884
+ with self._lock:
1885
+ return self._revision_projection_conn(
1886
+ self._conn, revision_id, _as_utc(now),
1887
+ )
1888
+
1889
+ def list_revision_projections(
1890
+ self,
1891
+ charter_key: Optional[str] = None,
1892
+ *,
1893
+ now: Optional[datetime] = None,
1894
+ ) -> list[Dict[str, Any]]:
1895
+ observed = _as_utc(now)
1896
+ with self._lock:
1897
+ if charter_key:
1898
+ rows = self._conn.execute(
1899
+ "SELECT revision_id FROM charter_revisions WHERE charter_key=? "
1900
+ "ORDER BY proposed_at DESC,revision_id",
1901
+ (str(charter_key),),
1902
+ ).fetchall()
1903
+ else:
1904
+ rows = self._conn.execute(
1905
+ "SELECT revision_id FROM charter_revisions "
1906
+ "ORDER BY proposed_at DESC,revision_id"
1907
+ ).fetchall()
1908
+ return [
1909
+ self._revision_projection_conn(
1910
+ self._conn, row["revision_id"], observed,
1911
+ )
1912
+ for row in rows
1913
+ ]
1914
+
1915
+ def _active_revision_conn(
1916
+ self,
1917
+ conn: sqlite3.Connection,
1918
+ charter_key: str,
1919
+ now: datetime,
1920
+ ) -> Optional[CharterRevisionV1]:
1921
+ rows = conn.execute(
1922
+ "SELECT revision_id,payload_json FROM charter_revisions "
1923
+ "WHERE charter_key=? ORDER BY proposed_at DESC,revision_id",
1924
+ (charter_key,),
1925
+ ).fetchall()
1926
+ active: list[CharterRevisionV1] = []
1927
+ for row in rows:
1928
+ projection = self._revision_projection_conn(
1929
+ conn, row["revision_id"], now,
1930
+ )
1931
+ if projection["lifecycle_status"] == "active":
1932
+ active.append(CharterRevisionV1.from_payload(
1933
+ json.loads(row["payload_json"]),
1934
+ ))
1935
+ if len(active) > 1:
1936
+ raise DriveGovernanceError(
1937
+ "lifecycle_integrity_error", "multiple active charter revisions",
1938
+ )
1939
+ return active[0] if active else None
1940
+
1941
+ def active_revision(
1942
+ self, charter_key: str = "default", *, now: Optional[datetime] = None,
1943
+ ) -> Optional[CharterRevisionV1]:
1944
+ with self._lock:
1945
+ return self._active_revision_conn(
1946
+ self._conn, str(charter_key), _as_utc(now),
1947
+ )
1948
+
1949
+ def _active_revisions_conn(
1950
+ self, conn: sqlite3.Connection, now: datetime,
1951
+ ) -> tuple[CharterRevisionV1, ...]:
1952
+ rows = conn.execute(
1953
+ "SELECT DISTINCT charter_key FROM charter_revisions "
1954
+ "ORDER BY charter_key"
1955
+ ).fetchall()
1956
+ return tuple(
1957
+ active
1958
+ for row in rows
1959
+ for active in (
1960
+ self._active_revision_conn(conn, row["charter_key"], now),
1961
+ )
1962
+ if active is not None
1963
+ )
1964
+
1965
+ def active_revisions(
1966
+ self, *, now: Optional[datetime] = None,
1967
+ ) -> tuple[CharterRevisionV1, ...]:
1968
+ """Return every active charter across keys in deterministic order."""
1969
+
1970
+ with self._lock:
1971
+ return self._active_revisions_conn(self._conn, _as_utc(now))
1972
+
1973
+ def _validate_transition_conn(
1974
+ self,
1975
+ conn: sqlite3.Connection,
1976
+ revision: CharterRevisionV1,
1977
+ transition: str,
1978
+ now: datetime,
1979
+ ) -> Optional[CharterRevisionV1]:
1980
+ current = self._active_revision_conn(conn, revision.charter_key, now)
1981
+ projection = self._revision_projection_conn(
1982
+ conn, revision.revision_id, now,
1983
+ )
1984
+ status = projection["lifecycle_status"]
1985
+ if transition == "activate":
1986
+ if status == "expired":
1987
+ raise DriveGovernanceError(
1988
+ "revision_expired", "expired charter revision cannot activate",
1989
+ )
1990
+ if status == "active":
1991
+ raise DriveGovernanceError(
1992
+ "revision_already_active", "charter revision is already active",
1993
+ )
1994
+ if status in {"superseded", "revoked"}:
1995
+ raise DriveGovernanceError(
1996
+ "revision_terminal", "terminal charter revision cannot reactivate",
1997
+ )
1998
+ if current is not None and revision.parent_revision_id != current.revision_id:
1999
+ raise DriveGovernanceError(
2000
+ "stale_charter_parent",
2001
+ "new charter parent is not the current active revision",
2002
+ )
2003
+ if current is None and revision.parent_revision_id:
2004
+ parent = conn.execute(
2005
+ "SELECT charter_key FROM charter_revisions WHERE revision_id=?",
2006
+ (revision.parent_revision_id,),
2007
+ ).fetchone()
2008
+ if parent is None or parent["charter_key"] != revision.charter_key:
2009
+ raise DriveGovernanceError(
2010
+ "unknown_charter_parent", "charter parent is unknown",
2011
+ )
2012
+ for drive_id, _weight in revision.drive_weights:
2013
+ drive_row = conn.execute(
2014
+ "SELECT payload_json FROM drive_definitions WHERE drive_id=?",
2015
+ (drive_id,),
2016
+ ).fetchone()
2017
+ if drive_row is None:
2018
+ raise DriveGovernanceError(
2019
+ "drive_unknown", f"charter drive is unknown: {drive_id}",
2020
+ )
2021
+ drive = DriveV1.from_payload(json.loads(drive_row["payload_json"]))
2022
+ drive_state = drive.state_at(now)
2023
+ if drive_state == "disabled":
2024
+ raise DriveGovernanceError(
2025
+ "drive_disabled", f"charter drive is disabled: {drive_id}",
2026
+ )
2027
+ if drive_state == "expired":
2028
+ raise DriveGovernanceError(
2029
+ "drive_expired", f"charter drive is expired: {drive_id}",
2030
+ )
2031
+ if not drive.scope.permits_child(revision.scope):
2032
+ # A charter projection may be as private as, or more
2033
+ # private than, its drive data. It must never make a
2034
+ # private drive's existence visible more broadly.
2035
+ raise DriveGovernanceError(
2036
+ "scope_broadening",
2037
+ "charter scope would broaden a referenced drive",
2038
+ )
2039
+ elif transition == "revoke":
2040
+ if current is None or current.revision_id != revision.revision_id:
2041
+ raise DriveGovernanceError(
2042
+ "revision_not_active", "only the active charter can be revoked",
2043
+ )
2044
+ else:
2045
+ raise DriveGovernanceError(
2046
+ "invalid_transition", "transition must be activate or revoke",
2047
+ )
2048
+ return current
2049
+
2050
+ def preflight_transition(
2051
+ self,
2052
+ revision_id: str,
2053
+ *,
2054
+ transition: str,
2055
+ now: Optional[datetime] = None,
2056
+ ) -> tuple[CharterRevisionV1, Optional[CharterRevisionV1]]:
2057
+ revision = self.get_revision(revision_id)
2058
+ if revision is None:
2059
+ raise DriveGovernanceError(
2060
+ "revision_unknown", "charter revision is unknown",
2061
+ )
2062
+ normalized = str(transition or "").strip().lower()
2063
+ with self._lock:
2064
+ current = self._validate_transition_conn(
2065
+ self._conn, revision, normalized, _as_utc(now),
2066
+ )
2067
+ return revision, current
2068
+
2069
+ def transition_operation(self, operation_id: str) -> Optional[Dict[str, Any]]:
2070
+ operation = _operation_id(operation_id)
2071
+ with self._lock:
2072
+ row = self._conn.execute(
2073
+ "SELECT * FROM charter_transition_operations WHERE operation_id=?",
2074
+ (operation,),
2075
+ ).fetchone()
2076
+ return dict(row) if row else None
2077
+
2078
+ def transition_authority_use(
2079
+ self, approval_request_id: str,
2080
+ ) -> Optional[Dict[str, Any]]:
2081
+ """Return validated application evidence for one approval request."""
2082
+
2083
+ request_id = _identifier(
2084
+ approval_request_id, "approval_request_id",
2085
+ )
2086
+ with self._lock:
2087
+ row = self._conn.execute(
2088
+ "SELECT u.approval_request_id,u.action_digest,u.operation_id,"
2089
+ "u.event_id,u.used_at,e.charter_key,e.revision_id,"
2090
+ "e.transition,e.decision_id,e.principal_id,e.payload_json,"
2091
+ "e.from_revision_id,e.authority_evidence,e.occurred_at "
2092
+ "FROM charter_authority_uses AS u "
2093
+ "JOIN charter_lifecycle_events AS e ON e.event_id=u.event_id "
2094
+ "WHERE u.approval_request_id=?",
2095
+ (request_id,),
2096
+ ).fetchone()
2097
+ if row is None:
2098
+ return None
2099
+ payload = self._validate_lifecycle_event(row)
2100
+ result = dict(row)
2101
+ result.pop("payload_json", None)
2102
+ result["payload"] = payload
2103
+ return result
2104
+
2105
+ @staticmethod
2106
+ def _transition_digest(
2107
+ *,
2108
+ revision_id: str,
2109
+ transition: str,
2110
+ binding: ActionBinding,
2111
+ approval_request_id: str,
2112
+ ) -> str:
2113
+ return _digest({
2114
+ "revision_id": revision_id,
2115
+ "transition": transition,
2116
+ "action_digest": binding.action_digest,
2117
+ "scope_digest": binding.scope_digest,
2118
+ "approval_request_id": approval_request_id,
2119
+ })
2120
+
2121
+ def _apply_transition(
2122
+ self,
2123
+ revision: CharterRevisionV1,
2124
+ *,
2125
+ transition: str,
2126
+ binding: ActionBinding,
2127
+ approval_request: Mapping[str, Any],
2128
+ operation_id: str,
2129
+ principal_id: str,
2130
+ require_no_active_charter: bool = False,
2131
+ now: Optional[datetime] = None,
2132
+ ) -> Dict[str, Any]:
2133
+ """Append an owner-ratified transition and atomically fence its use."""
2134
+
2135
+ observed = _as_utc(now)
2136
+ operation = _operation_id(operation_id)
2137
+ request_id = _identifier(
2138
+ approval_request.get("request_id"), "approval_request_id",
2139
+ )
2140
+ decision_id = _identifier(
2141
+ approval_request.get("decision_id"), "decision_id",
2142
+ )
2143
+ evidence = _text(
2144
+ approval_request.get("authority_evidence"),
2145
+ "authority_evidence", 256,
2146
+ )
2147
+ normalized = str(transition or "").strip().lower()
2148
+ transition_digest = self._transition_digest(
2149
+ revision_id=revision.revision_id,
2150
+ transition=normalized,
2151
+ binding=binding,
2152
+ approval_request_id=request_id,
2153
+ )
2154
+ with self._lock, self._conn:
2155
+ self._conn.execute("BEGIN IMMEDIATE")
2156
+ prior = self._conn.execute(
2157
+ "SELECT * FROM charter_transition_operations WHERE operation_id=?",
2158
+ (operation,),
2159
+ ).fetchone()
2160
+ if prior is not None:
2161
+ if prior["transition_digest"] != transition_digest:
2162
+ raise DriveGovernanceError(
2163
+ "operation_replay_conflict",
2164
+ "ratification operation replay changed its binding",
2165
+ )
2166
+ projection = self._revision_projection_conn(
2167
+ self._conn, revision.revision_id, observed,
2168
+ )
2169
+ projection.update({
2170
+ "enabled": True,
2171
+ "status": f"charter_{normalized}_replayed",
2172
+ "event_id": prior["event_id"],
2173
+ "replayed": True,
2174
+ })
2175
+ return projection
2176
+
2177
+ used = self._conn.execute(
2178
+ "SELECT * FROM charter_authority_uses WHERE approval_request_id=?",
2179
+ (request_id,),
2180
+ ).fetchone()
2181
+ if used is not None:
2182
+ raise DriveGovernanceError(
2183
+ "authority_replay",
2184
+ "approval request was already consumed by another transition",
2185
+ )
2186
+
2187
+ current = self._validate_transition_conn(
2188
+ self._conn, revision, normalized, observed,
2189
+ )
2190
+ if (
2191
+ require_no_active_charter
2192
+ and self._active_revisions_conn(self._conn, observed)
2193
+ ):
2194
+ raise DriveGovernanceError(
2195
+ "bootstrap_transition_held",
2196
+ "bootstrap may activate only the first global root charter",
2197
+ )
2198
+ event_payload = {
2199
+ "schema": "CharterLifecycleEventV1", "version": 1,
2200
+ "charter_key": revision.charter_key,
2201
+ "revision_id": revision.revision_id,
2202
+ "transition": normalized,
2203
+ "from_revision_id": (
2204
+ current.revision_id if current is not None else None
2205
+ ),
2206
+ "action_digest": binding.action_digest,
2207
+ "approval_request_id": request_id,
2208
+ "decision_id": decision_id,
2209
+ "principal_id": principal_id,
2210
+ "authority_evidence": evidence,
2211
+ "occurred_at": _iso(observed),
2212
+ }
2213
+ event_id = f"charter-event:{_digest(event_payload)[:24]}"
2214
+
2215
+ if normalized == "activate" and current is not None:
2216
+ supersede_payload = {
2217
+ "schema": "CharterLifecycleEventV1", "version": 1,
2218
+ "charter_key": revision.charter_key,
2219
+ "revision_id": current.revision_id,
2220
+ "transition": "supersede",
2221
+ "from_revision_id": revision.revision_id,
2222
+ "action_digest": binding.action_digest,
2223
+ "approval_request_id": request_id,
2224
+ "decision_id": decision_id,
2225
+ "principal_id": principal_id,
2226
+ "authority_evidence": evidence,
2227
+ "occurred_at": _iso(observed),
2228
+ }
2229
+ supersede_id = (
2230
+ f"charter-event:{_digest(supersede_payload)[:24]}"
2231
+ )
2232
+ self._conn.execute(
2233
+ "INSERT INTO charter_lifecycle_events "
2234
+ "(event_id,charter_key,revision_id,transition,from_revision_id,"
2235
+ "action_digest,approval_request_id,decision_id,principal_id,"
2236
+ "authority_evidence,occurred_at,payload_json) "
2237
+ "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",
2238
+ (
2239
+ supersede_id, revision.charter_key, current.revision_id,
2240
+ "supersede", revision.revision_id, binding.action_digest,
2241
+ request_id, decision_id, principal_id, evidence,
2242
+ _iso(observed), _canonical(supersede_payload),
2243
+ ),
2244
+ )
2245
+
2246
+ self._conn.execute(
2247
+ "INSERT INTO charter_lifecycle_events "
2248
+ "(event_id,charter_key,revision_id,transition,from_revision_id,"
2249
+ "action_digest,approval_request_id,decision_id,principal_id,"
2250
+ "authority_evidence,occurred_at,payload_json) "
2251
+ "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",
2252
+ (
2253
+ event_id, revision.charter_key, revision.revision_id,
2254
+ normalized,
2255
+ current.revision_id if current is not None else None,
2256
+ binding.action_digest, request_id, decision_id, principal_id,
2257
+ evidence, _iso(observed), _canonical(event_payload),
2258
+ ),
2259
+ )
2260
+ self._conn.execute(
2261
+ "INSERT INTO charter_authority_uses "
2262
+ "(approval_request_id,action_digest,operation_id,event_id,used_at) "
2263
+ "VALUES (?,?,?,?,?)",
2264
+ (
2265
+ request_id, binding.action_digest, operation, event_id,
2266
+ _iso(observed),
2267
+ ),
2268
+ )
2269
+ self._conn.execute(
2270
+ "INSERT INTO charter_transition_operations "
2271
+ "(operation_id,transition_digest,revision_id,transition,"
2272
+ "approval_request_id,event_id,created_at) VALUES (?,?,?,?,?,?,?)",
2273
+ (
2274
+ operation, transition_digest, revision.revision_id,
2275
+ normalized, request_id, event_id, _iso(observed),
2276
+ ),
2277
+ )
2278
+ projection = self._revision_projection_conn(
2279
+ self._conn, revision.revision_id, observed,
2280
+ )
2281
+ projection.update({
2282
+ "enabled": True,
2283
+ "status": f"charter_{normalized}d",
2284
+ "event_id": event_id,
2285
+ "replayed": False,
2286
+ })
2287
+ return projection
2288
+
2289
+ def lifecycle_events(self, charter_key: str = "default") -> list[Dict[str, Any]]:
2290
+ with self._lock:
2291
+ rows = self._conn.execute(
2292
+ "SELECT * FROM charter_lifecycle_events WHERE charter_key=? "
2293
+ "ORDER BY event_seq", (str(charter_key),),
2294
+ ).fetchall()
2295
+ result = []
2296
+ for row in rows:
2297
+ item = dict(row)
2298
+ item["payload"] = self._validate_lifecycle_event(row)
2299
+ item.pop("payload_json")
2300
+ result.append(item)
2301
+ return result
2302
+
2303
+ def observer_projection(
2304
+ self,
2305
+ *,
2306
+ viewer_person_id: str,
2307
+ owner_person_id: str,
2308
+ audiences: set[str] | frozenset[str] = frozenset(),
2309
+ charter_key: str = "default",
2310
+ now: Optional[datetime] = None,
2311
+ signal_limit: int = 100,
2312
+ ) -> Dict[str, Any]:
2313
+ observed = _as_utc(now)
2314
+ revisions = self.list_revision_projections(charter_key, now=observed)
2315
+ visible_revisions = [
2316
+ item for item in revisions
2317
+ if ScopeV1(**dict(item["scope"])).visible_to(
2318
+ viewer_person_id=viewer_person_id,
2319
+ owner_person_id=owner_person_id,
2320
+ audiences=audiences,
2321
+ )
2322
+ ]
2323
+ drives = [
2324
+ item for item in self.list_drives()
2325
+ if item.scope.visible_to(
2326
+ viewer_person_id=viewer_person_id,
2327
+ owner_person_id=owner_person_id,
2328
+ audiences=audiences,
2329
+ )
2330
+ ]
2331
+ bounded_limit = max(1, min(int(signal_limit), 500))
2332
+ with self._lock:
2333
+ rows = self._conn.execute(
2334
+ "SELECT payload_json FROM drive_signals "
2335
+ "ORDER BY observed_at DESC,signal_seq DESC LIMIT ?",
2336
+ (bounded_limit,),
2337
+ ).fetchall()
2338
+ signals = [
2339
+ item for item in (
2340
+ DriveSignalV1.from_payload(json.loads(row["payload_json"]))
2341
+ for row in rows
2342
+ )
2343
+ if item.scope.visible_to(
2344
+ viewer_person_id=viewer_person_id,
2345
+ owner_person_id=owner_person_id,
2346
+ audiences=audiences,
2347
+ )
2348
+ ]
2349
+ active = self.active_revision(charter_key, now=observed)
2350
+ active_visible = bool(
2351
+ active
2352
+ and active.scope.visible_to(
2353
+ viewer_person_id=viewer_person_id,
2354
+ owner_person_id=owner_person_id,
2355
+ audiences=audiences,
2356
+ )
2357
+ )
2358
+ return {
2359
+ "schema": "DriveGovernanceObserverV1", "version": 1,
2360
+ "charter_key": charter_key,
2361
+ "active_charter_revision_id": (
2362
+ active.revision_id if active_visible and active else None
2363
+ ),
2364
+ "charter_revisions": visible_revisions,
2365
+ "drives": [
2366
+ {**item.payload(), "effective_state": item.state_at(observed)}
2367
+ for item in drives
2368
+ ],
2369
+ "signals": [
2370
+ {**item.payload(), "effective_state": item.state_at(observed)}
2371
+ for item in signals
2372
+ ],
2373
+ "generated_at": _iso(observed),
2374
+ }
2375
+
2376
+
2377
+ class DriveGovernance:
2378
+ """Mode-gated service reusing existing approvals for charter authority."""
2379
+
2380
+ def __init__(
2381
+ self,
2382
+ store: Optional[DriveGovernanceStore],
2383
+ approval_store: Optional[ApprovalAuthorityStore],
2384
+ *,
2385
+ mode: Optional[str] = None,
2386
+ ) -> None:
2387
+ self.store = store
2388
+ self.approval_store = approval_store
2389
+ self.mode = _normalized_mode(mode)
2390
+ if self.mode != "off" and self.store is None:
2391
+ raise DriveGovernanceError(
2392
+ "store_required", "drive governance store is required",
2393
+ )
2394
+
2395
+ @classmethod
2396
+ def lazy(
2397
+ cls,
2398
+ db_path: str | os.PathLike[str],
2399
+ *,
2400
+ approval_db_path: Optional[str | os.PathLike[str]] = None,
2401
+ mode: Optional[str] = None,
2402
+ ) -> "DriveGovernance":
2403
+ selected = _normalized_mode(mode)
2404
+ if selected == "off":
2405
+ # Default-off means no database, directory, or approval state is
2406
+ # created merely because a host imports or constructs the module.
2407
+ return cls(None, None, mode="off")
2408
+ store = DriveGovernanceStore(db_path)
2409
+ approval_store = ApprovalAuthorityStore(approval_db_path)
2410
+ return cls(store, approval_store, mode=selected)
2411
+
2412
+ def _store(self) -> DriveGovernanceStore:
2413
+ if self.store is None:
2414
+ raise DriveGovernanceError(
2415
+ "store_required", "drive governance store is unavailable",
2416
+ )
2417
+ return self.store
2418
+
2419
+ def register_drive(
2420
+ self,
2421
+ drive: DriveV1,
2422
+ *,
2423
+ operation_id: str,
2424
+ now: Optional[datetime] = None,
2425
+ ) -> Dict[str, Any]:
2426
+ if self.mode == "off":
2427
+ return {"enabled": False, "status": "off"}
2428
+ return self._store().register_drive(
2429
+ drive, operation_id=operation_id, now=now,
2430
+ )
2431
+
2432
+ def record_signal(
2433
+ self,
2434
+ signal: DriveSignalV1,
2435
+ *,
2436
+ operation_id: str,
2437
+ now: Optional[datetime] = None,
2438
+ ) -> Dict[str, Any]:
2439
+ if self.mode == "off":
2440
+ return {"enabled": False, "status": "off"}
2441
+ if self.mode == "bootstrap":
2442
+ raise DriveGovernanceError(
2443
+ "bootstrap_operation_held",
2444
+ "drive signals are held during initial charter bootstrap",
2445
+ )
2446
+ return self._store().record_signal(
2447
+ signal, operation_id=operation_id, now=now,
2448
+ )
2449
+
2450
+ def propose_charter(
2451
+ self,
2452
+ revision: CharterRevisionV1,
2453
+ *,
2454
+ operation_id: str,
2455
+ now: Optional[datetime] = None,
2456
+ ) -> Dict[str, Any]:
2457
+ if self.mode == "off":
2458
+ return {"enabled": False, "status": "off"}
2459
+ result = self._store().propose_revision(
2460
+ revision, operation_id=operation_id, now=now,
2461
+ )
2462
+ result.setdefault("status", (
2463
+ "charter_proposal_replayed" if result.get("replayed")
2464
+ else "charter_proposed"
2465
+ ))
2466
+ result["effect_executed"] = False
2467
+ return result
2468
+
2469
+ def ensure_transition_request(
2470
+ self,
2471
+ revision_id: str,
2472
+ *,
2473
+ transition: str,
2474
+ ttl_seconds: int = 3600,
2475
+ now: Optional[datetime] = None,
2476
+ ) -> Dict[str, Any]:
2477
+ if self.mode == "off":
2478
+ return {"enabled": False, "status": "off"}
2479
+ observed = _as_utc(now)
2480
+ store = self._store()
2481
+ revision, current = store.preflight_transition(
2482
+ revision_id, transition=transition, now=observed,
2483
+ )
2484
+ normalized = str(transition).strip().lower()
2485
+ if self.mode == "bootstrap" and (
2486
+ normalized != "activate"
2487
+ or current is not None
2488
+ or revision.parent_revision_id is not None
2489
+ or store.active_revisions(now=observed)
2490
+ ):
2491
+ raise DriveGovernanceError(
2492
+ "bootstrap_transition_held",
2493
+ "bootstrap may activate only the first global root charter",
2494
+ )
2495
+ binding = charter_transition_binding(
2496
+ revision,
2497
+ transition=normalized,
2498
+ expected_active_revision_id=(
2499
+ current.revision_id if current is not None else None
2500
+ ),
2501
+ )
2502
+ if self.mode == "shadow":
2503
+ return {
2504
+ "enabled": True,
2505
+ "status": "shadow_transition_candidate",
2506
+ "transition": normalized,
2507
+ "revision_id": revision.revision_id,
2508
+ "action_digest": binding.action_digest,
2509
+ "scope_digest": binding.scope_digest,
2510
+ "expected_active_revision_id": (
2511
+ current.revision_id if current else None
2512
+ ),
2513
+ "effect_executed": False,
2514
+ }
2515
+ if self.approval_store is None:
2516
+ raise DriveGovernanceError(
2517
+ "approval_store_required", "approval authority store is unavailable",
2518
+ )
2519
+ ttl = _bounded_int(
2520
+ ttl_seconds, "transition request ttl_seconds",
2521
+ minimum=60, maximum=24 * 60 * 60,
2522
+ )
2523
+ job_id = f"charter-transition:{binding.action_digest[:24]}"
2524
+ subject = charter_transition_subject(
2525
+ revision, transition=normalized,
2526
+ )
2527
+ presentation = charter_transition_presentation(
2528
+ revision, transition=normalized, binding=binding,
2529
+ )
2530
+ request = self.approval_store.ensure_request(
2531
+ job_id=job_id,
2532
+ binding=binding,
2533
+ ttl_seconds=ttl,
2534
+ presentation=presentation,
2535
+ subject=subject,
2536
+ now=observed,
2537
+ )
2538
+ return {
2539
+ **request,
2540
+ "enabled": True,
2541
+ "transition": normalized,
2542
+ "revision_id": revision.revision_id,
2543
+ "effect_executed": False,
2544
+ }
2545
+
2546
+ def _validated_transition_approval(
2547
+ self,
2548
+ request_id: str,
2549
+ *,
2550
+ now: Optional[datetime] = None,
2551
+ ) -> tuple[Dict[str, Any], CharterRevisionV1, str, bool, Optional[Dict[str, Any]]]:
2552
+ if self.approval_store is None:
2553
+ raise DriveGovernanceError(
2554
+ "approval_store_required",
2555
+ "approval authority store is unavailable",
2556
+ )
2557
+ observed = _as_utc(now)
2558
+ request = self.approval_store.get_request(request_id, now=observed)
2559
+ if request is None:
2560
+ raise DriveGovernanceError(
2561
+ "approval_request_missing", "approval request was not found",
2562
+ )
2563
+ subject = request.get("subject")
2564
+ if not isinstance(subject, Mapping) or subject.get("kind") !=\
2565
+ "charter_transition":
2566
+ raise DriveGovernanceError(
2567
+ "approval_subject_unavailable",
2568
+ "approval request is not a charter transition subject",
2569
+ )
2570
+ normalized = str(subject.get("action") or "").strip().lower()
2571
+ if normalized not in _TRANSITIONS:
2572
+ raise DriveGovernanceError(
2573
+ "approval_subject_invalid",
2574
+ "charter transition approval action is invalid",
2575
+ )
2576
+ revision = self._store().get_revision(str(subject.get("subject_id") or ""))
2577
+ if revision is None or subject.get("revision") != revision.content_digest:
2578
+ raise DriveGovernanceError(
2579
+ "approval_subject_unavailable",
2580
+ "charter transition approval subject is orphaned",
2581
+ )
2582
+ expected_subject = charter_transition_subject(
2583
+ revision, transition=normalized,
2584
+ ).payload()
2585
+ if dict(subject) != expected_subject:
2586
+ raise DriveGovernanceError(
2587
+ "approval_subject_invalid",
2588
+ "charter transition approval subject binding is invalid",
2589
+ )
2590
+
2591
+ scope = request.get("scope")
2592
+ constraints = scope.get("constraints") if isinstance(scope, Mapping) else None
2593
+ expected_constraints = {
2594
+ "charter_key_digest": _digest(revision.charter_key),
2595
+ "revision_id_digest": _digest(revision.revision_id),
2596
+ "content_digest": revision.content_digest,
2597
+ }
2598
+ valid_scope = bool(
2599
+ isinstance(scope, Mapping)
2600
+ and set(scope) == {
2601
+ "version", "job_type", "action_name", "risk", "constraints",
2602
+ }
2603
+ and scope.get("version") == 1
2604
+ and scope.get("job_type") == "charter_governance"
2605
+ and scope.get("action_name") == f"charter_revision_{normalized}"
2606
+ and scope.get("risk") == "authority_mutation"
2607
+ and isinstance(constraints, Mapping)
2608
+ and set(constraints) == {
2609
+ *expected_constraints,
2610
+ "expected_active_revision_digest",
2611
+ }
2612
+ and all(
2613
+ constraints.get(key) == value
2614
+ for key, value in expected_constraints.items()
2615
+ )
2616
+ and re.fullmatch(
2617
+ r"[0-9a-f]{64}",
2618
+ str(constraints.get("expected_active_revision_digest") or ""),
2619
+ ) is not None
2620
+ and _digest(scope) == request.get("scope_digest")
2621
+ )
2622
+ if not valid_scope:
2623
+ raise DriveGovernanceError(
2624
+ "approval_binding_invalid",
2625
+ "charter transition approval scope is invalid",
2626
+ )
2627
+ expected_presentation = charter_transition_presentation(
2628
+ revision,
2629
+ transition=normalized,
2630
+ binding=ActionBinding(
2631
+ action_digest=str(request.get("action_digest") or ""),
2632
+ scope=dict(scope),
2633
+ scope_digest=str(request.get("scope_digest") or ""),
2634
+ ),
2635
+ )
2636
+ if request.get("presentation") != expected_presentation:
2637
+ raise DriveGovernanceError(
2638
+ "approval_presentation_invalid",
2639
+ "charter transition approval presentation is invalid",
2640
+ )
2641
+ if request.get("job_id") != (
2642
+ f"charter-transition:{str(request.get('action_digest') or '')[:24]}"
2643
+ ):
2644
+ raise DriveGovernanceError(
2645
+ "approval_binding_invalid",
2646
+ "charter transition approval identifier is invalid",
2647
+ )
2648
+ if request.get("status") in {"approved", "rejected"}:
2649
+ decided_by = str(request.get("decided_by") or "").strip()
2650
+ evidence = str(request.get("authority_evidence") or "").strip()
2651
+ evidence_prefix = f"scoped_principal:{decided_by}:"
2652
+ credential_id = (
2653
+ evidence[len(evidence_prefix):]
2654
+ if decided_by and evidence.startswith(evidence_prefix)
2655
+ else ""
2656
+ )
2657
+ try:
2658
+ _identifier(decided_by, "decided_by")
2659
+ _identifier(credential_id, "decision_credential_id")
2660
+ except DriveGovernanceError as exc:
2661
+ raise DriveGovernanceError(
2662
+ "approval_authority_integrity_error",
2663
+ "charter transition decision authority is invalid",
2664
+ ) from exc
2665
+
2666
+ use = self._store().transition_authority_use(request["request_id"])
2667
+ if use is not None:
2668
+ from_revision_id = use.get("from_revision_id")
2669
+ applied_binding = charter_transition_binding(
2670
+ revision,
2671
+ transition=normalized,
2672
+ expected_active_revision_id=from_revision_id,
2673
+ )
2674
+ if (
2675
+ use.get("revision_id") != revision.revision_id
2676
+ or use.get("transition") != normalized
2677
+ or use.get("action_digest") != request.get("action_digest")
2678
+ or applied_binding.action_digest != request.get("action_digest")
2679
+ or applied_binding.scope_digest != request.get("scope_digest")
2680
+ ):
2681
+ raise DriveGovernanceError(
2682
+ "approval_application_integrity_error",
2683
+ "charter transition application does not match its approval",
2684
+ )
2685
+ current_binding_matches = False
2686
+ else:
2687
+ store = self._store()
2688
+ current = store.active_revision(
2689
+ revision.charter_key, now=observed,
2690
+ )
2691
+ current_binding = charter_transition_binding(
2692
+ revision,
2693
+ transition=normalized,
2694
+ expected_active_revision_id=(
2695
+ current.revision_id if current is not None else None
2696
+ ),
2697
+ )
2698
+ current_binding_matches = bool(
2699
+ current_binding.action_digest == request.get("action_digest")
2700
+ and current_binding.scope_digest == request.get("scope_digest")
2701
+ and not (
2702
+ self.mode == "bootstrap"
2703
+ and store.active_revisions(now=observed)
2704
+ )
2705
+ )
2706
+ return request, revision, normalized, current_binding_matches, use
2707
+
2708
+ def transition_approval_projection(
2709
+ self,
2710
+ request_id: str,
2711
+ *,
2712
+ now: Optional[datetime] = None,
2713
+ ) -> Dict[str, Any]:
2714
+ """Return one redacted typed approval, never a raw authority row."""
2715
+
2716
+ observed = _as_utc(now)
2717
+ request, revision, transition, binding_current, use =\
2718
+ self._validated_transition_approval(request_id, now=observed)
2719
+ if use is not None:
2720
+ status = "approved_applied"
2721
+ application = {
2722
+ "status": "applied",
2723
+ "event_id": use["event_id"],
2724
+ "operation_id": use["operation_id"],
2725
+ "applied_at": use["used_at"],
2726
+ }
2727
+ elif request["status"] == "approved" and binding_current:
2728
+ status = "approved_unapplied"
2729
+ application = {
2730
+ "status": "recovery_required",
2731
+ "event_id": None,
2732
+ "operation_id": None,
2733
+ "applied_at": None,
2734
+ }
2735
+ elif request["status"] == "approved":
2736
+ status = "approved_stale"
2737
+ application = {
2738
+ "status": "new_request_required",
2739
+ "event_id": None,
2740
+ "operation_id": None,
2741
+ "applied_at": None,
2742
+ }
2743
+ elif request["status"] == "rejected":
2744
+ status = "rejected"
2745
+ application = {
2746
+ "status": "not_applicable",
2747
+ "event_id": None,
2748
+ "operation_id": None,
2749
+ "applied_at": None,
2750
+ }
2751
+ elif request["status"] == "pending" and not binding_current:
2752
+ status = "stale_pending"
2753
+ application = {
2754
+ "status": "binding_changed",
2755
+ "event_id": None,
2756
+ "operation_id": None,
2757
+ "applied_at": None,
2758
+ }
2759
+ else:
2760
+ status = request["status"]
2761
+ application = {
2762
+ "status": "awaiting_decision",
2763
+ "event_id": None,
2764
+ "operation_id": None,
2765
+ "applied_at": None,
2766
+ }
2767
+ return {
2768
+ "schema": CHARTER_TRANSITION_APPROVAL_PROJECTION_SCHEMA,
2769
+ "version": 1,
2770
+ "subject_kind": "charter_transition",
2771
+ "subject_id": revision.revision_id,
2772
+ "subject_revision": revision.content_digest,
2773
+ "subject_action": transition,
2774
+ "subject_digest": request["subject_digest"],
2775
+ "request_id": request["request_id"],
2776
+ "request_digest": request["request_digest"],
2777
+ "request_digest_version": request["request_digest_version"],
2778
+ "action_digest": request["action_digest"],
2779
+ "scope_digest": request["scope_digest"],
2780
+ "binding_digest": request["binding_digest"],
2781
+ "presentation": request["presentation"],
2782
+ "presentation_digest": request["presentation_digest"],
2783
+ "status": status,
2784
+ "authority_status": request["status"],
2785
+ "binding_current": binding_current,
2786
+ "created_at": request["created_at"],
2787
+ "expires_at": request["expires_at"],
2788
+ "decision": request.get("decision"),
2789
+ "decision_id": request.get("decision_id"),
2790
+ "decided_at": request.get("decided_at"),
2791
+ "decided_by": request.get("decided_by"),
2792
+ "authority_evidence": request.get("authority_evidence"),
2793
+ "application": application,
2794
+ "observed_at": _iso(observed),
2795
+ }
2796
+
2797
+ def list_transition_approval_projections(
2798
+ self,
2799
+ *,
2800
+ status: Optional[str] = None,
2801
+ limit: int = 100,
2802
+ now: Optional[datetime] = None,
2803
+ ) -> list[Dict[str, Any]]:
2804
+ return self.transition_approval_inventory(
2805
+ status=status, limit=limit, now=now,
2806
+ )["requests"]
2807
+
2808
+ def transition_approval_inventory(
2809
+ self,
2810
+ *,
2811
+ status: Optional[str] = None,
2812
+ limit: int = 100,
2813
+ now: Optional[datetime] = None,
2814
+ ) -> Dict[str, Any]:
2815
+ """Return valid projections plus a bounded count of hidden invalids."""
2816
+
2817
+ if self.approval_store is None:
2818
+ return {
2819
+ "requests": [], "invalid_hidden_count": 0,
2820
+ "candidate_count": 0, "complete": True,
2821
+ }
2822
+ observed = _as_utc(now)
2823
+ inspection = self.approval_store.inspect_subject_requests(
2824
+ subject_kind="charter_transition",
2825
+ job_prefix="charter-transition:",
2826
+ limit=500,
2827
+ now=observed,
2828
+ )
2829
+ candidates = inspection["requests"]
2830
+ invalid_hidden_count = int(inspection["invalid_hidden_count"])
2831
+ projections: list[Dict[str, Any]] = []
2832
+ bounded_limit = max(1, min(int(limit), 500))
2833
+ projection_overflow = False
2834
+ for candidate in candidates:
2835
+ try:
2836
+ projection = self.transition_approval_projection(
2837
+ candidate["request_id"], now=observed,
2838
+ )
2839
+ except DriveGovernanceError as exc:
2840
+ if exc.code in {
2841
+ "approval_subject_unavailable", "approval_subject_invalid",
2842
+ "approval_binding_invalid", "approval_presentation_invalid",
2843
+ "approval_application_integrity_error",
2844
+ "approval_authority_integrity_error",
2845
+ }:
2846
+ invalid_hidden_count += 1
2847
+ continue
2848
+ raise
2849
+ if status and projection["status"] != status:
2850
+ continue
2851
+ if len(projections) < bounded_limit:
2852
+ projections.append(projection)
2853
+ else:
2854
+ projection_overflow = True
2855
+ return {
2856
+ "requests": projections,
2857
+ "invalid_hidden_count": invalid_hidden_count,
2858
+ "candidate_count": int(inspection["candidate_count"]),
2859
+ "complete": bool(
2860
+ inspection["complete"] and not projection_overflow
2861
+ ),
2862
+ }
2863
+
2864
+ @staticmethod
2865
+ def _validate_transition_decision_authority(authority: Any) -> tuple[str, str]:
2866
+ allowed = bool(
2867
+ authority is not None
2868
+ and getattr(authority, "authenticated", False)
2869
+ and not getattr(authority, "legacy", False)
2870
+ and not getattr(authority, "anonymous", False)
2871
+ and callable(getattr(authority, "has_scope", None))
2872
+ and authority.has_scope("charter:approval-decide")
2873
+ and "owner" in set(getattr(authority, "audiences", ()))
2874
+ and str(getattr(authority, "principal_id", "")).strip()
2875
+ and str(getattr(authority, "credential_id", "")).strip()
2876
+ )
2877
+ if not allowed:
2878
+ raise DriveGovernanceError(
2879
+ "owner_charter_approval_authority_required",
2880
+ "scoped authenticated owner charter approval authority is required",
2881
+ )
2882
+ return (
2883
+ str(authority.principal_id).strip(),
2884
+ str(authority.credential_id).strip(),
2885
+ )
2886
+
2887
+ def decide_transition_request(
2888
+ self,
2889
+ request_id: str,
2890
+ *,
2891
+ decision: str,
2892
+ decision_id: str,
2893
+ expected_action_digest: str,
2894
+ expected_request_digest: str,
2895
+ authority: Any,
2896
+ now: Optional[datetime] = None,
2897
+ ) -> Dict[str, Any]:
2898
+ """Decide and converge one exact charter transition without grants."""
2899
+
2900
+ if self.mode not in {"bootstrap", "live"}:
2901
+ raise DriveGovernanceError(
2902
+ "transition_not_authoritative",
2903
+ "charter transitions require bootstrap or live mode",
2904
+ )
2905
+ principal, credential = self._validate_transition_decision_authority(
2906
+ authority,
2907
+ )
2908
+ observed = _as_utc(now)
2909
+ request, revision, transition, binding_current, use =\
2910
+ self._validated_transition_approval(request_id, now=observed)
2911
+ if expected_action_digest != request["action_digest"]:
2912
+ raise DriveGovernanceError(
2913
+ "stale_action_digest",
2914
+ "decision does not match the immutable charter transition",
2915
+ )
2916
+ if expected_request_digest != request["request_digest"]:
2917
+ raise DriveGovernanceError(
2918
+ "stale_request_digest",
2919
+ "decision does not match the displayed subject, presentation, and expiry",
2920
+ )
2921
+ if request["status"] == "pending" and not binding_current:
2922
+ raise DriveGovernanceError(
2923
+ "approval_binding_stale",
2924
+ "charter transition binding changed before the decision",
2925
+ )
2926
+ if self.approval_store is None:
2927
+ raise DriveGovernanceError(
2928
+ "approval_store_required", "approval authority store is unavailable",
2929
+ )
2930
+ self.approval_store.decide(
2931
+ request["request_id"],
2932
+ decision=decision,
2933
+ decision_id=decision_id,
2934
+ expected_action_digest=expected_action_digest,
2935
+ decided_by=principal,
2936
+ authority_evidence=f"scoped_principal:{principal}:{credential}",
2937
+ grant_scope=None,
2938
+ now=observed,
2939
+ )
2940
+ if str(decision).strip().lower() == "approve" and use is None:
2941
+ operation_id = "charter-decision:" + _digest({
2942
+ "request_id": request["request_id"],
2943
+ "decision_id": decision_id,
2944
+ })[:32]
2945
+ self.ratify_transition(
2946
+ revision.revision_id,
2947
+ transition=transition,
2948
+ approval_request_id=request["request_id"],
2949
+ operation_id=operation_id,
2950
+ authority=authority,
2951
+ now=observed,
2952
+ )
2953
+ return self.transition_approval_projection(
2954
+ request["request_id"], now=observed,
2955
+ )
2956
+
2957
+ @staticmethod
2958
+ def _validate_owner_authority(authority: Any) -> tuple[str, str]:
2959
+ allowed = bool(
2960
+ authority is not None
2961
+ and getattr(authority, "authenticated", False)
2962
+ and not getattr(authority, "legacy", False)
2963
+ and not getattr(authority, "anonymous", False)
2964
+ and callable(getattr(authority, "has_scope", None))
2965
+ and (
2966
+ authority.has_scope("approvals:decide")
2967
+ or authority.has_scope("charter:approval-decide")
2968
+ )
2969
+ and "owner" in set(getattr(authority, "audiences", ()))
2970
+ and str(getattr(authority, "principal_id", "")).strip()
2971
+ and str(getattr(authority, "credential_id", "")).strip()
2972
+ )
2973
+ if not allowed:
2974
+ raise DriveGovernanceError(
2975
+ "owner_authority_required",
2976
+ "scoped authenticated owner approval authority is required",
2977
+ )
2978
+ principal = str(authority.principal_id).strip()
2979
+ credential = str(authority.credential_id).strip()
2980
+ return principal, credential
2981
+
2982
+ def ratify_transition(
2983
+ self,
2984
+ revision_id: str,
2985
+ *,
2986
+ transition: str,
2987
+ approval_request_id: str,
2988
+ operation_id: str,
2989
+ authority: Any,
2990
+ now: Optional[datetime] = None,
2991
+ ) -> Dict[str, Any]:
2992
+ """Activate/revoke only from an exact owner-scoped approval decision."""
2993
+
2994
+ if self.mode not in {"bootstrap", "live"}:
2995
+ raise DriveGovernanceError(
2996
+ "transition_not_authoritative",
2997
+ "charter transitions require bootstrap or live mode",
2998
+ )
2999
+ principal, credential = self._validate_owner_authority(authority)
3000
+ normalized = str(transition or "").strip().lower()
3001
+ if normalized not in _TRANSITIONS:
3002
+ raise DriveGovernanceError(
3003
+ "invalid_transition", "transition must be activate or revoke",
3004
+ )
3005
+ request_id = _identifier(
3006
+ approval_request_id, "approval_request_id",
3007
+ )
3008
+ operation = _operation_id(operation_id)
3009
+ store = self._store()
3010
+
3011
+ # Exact retries remain idempotent after the lifecycle commit. A changed
3012
+ # request, revision, or transition using the same operation is refused.
3013
+ prior = store.transition_operation(operation)
3014
+ if prior is not None:
3015
+ if (
3016
+ prior["revision_id"] != revision_id
3017
+ or prior["transition"] != normalized
3018
+ or prior["approval_request_id"] != request_id
3019
+ ):
3020
+ raise DriveGovernanceError(
3021
+ "operation_replay_conflict",
3022
+ "ratification operation replay changed its immutable first use",
3023
+ )
3024
+ projection = store.revision_projection(revision_id, now=now)
3025
+ projection.update({
3026
+ "enabled": True,
3027
+ "status": f"charter_{normalized}_replayed",
3028
+ "event_id": prior["event_id"],
3029
+ "replayed": True,
3030
+ })
3031
+ return projection
3032
+
3033
+ revision = store.get_revision(revision_id)
3034
+ if revision is None:
3035
+ raise DriveGovernanceError(
3036
+ "revision_unknown", "charter revision is unknown",
3037
+ )
3038
+ observed = _as_utc(now)
3039
+ current = store.active_revision(revision.charter_key, now=observed)
3040
+ if self.mode == "bootstrap" and (
3041
+ normalized != "activate"
3042
+ or current is not None
3043
+ or revision.parent_revision_id is not None
3044
+ or store.active_revisions(now=observed)
3045
+ ):
3046
+ raise DriveGovernanceError(
3047
+ "bootstrap_transition_held",
3048
+ "bootstrap may activate only the first global root charter",
3049
+ )
3050
+ binding = charter_transition_binding(
3051
+ revision,
3052
+ transition=normalized,
3053
+ expected_active_revision_id=(
3054
+ current.revision_id if current is not None else None
3055
+ ),
3056
+ )
3057
+ if self.approval_store is None:
3058
+ raise DriveGovernanceError(
3059
+ "approval_store_required", "approval authority store is unavailable",
3060
+ )
3061
+ request = self.approval_store.get_request(request_id, now=observed)
3062
+ if request is None:
3063
+ raise DriveGovernanceError(
3064
+ "approval_request_missing", "approval request was not found",
3065
+ )
3066
+ expires_at = _parse_time(request.get("expires_at"), field="approval expires_at")
3067
+ decided_at = (
3068
+ _parse_time(request.get("decided_at"), field="approval decided_at")
3069
+ if request.get("decided_at") else None
3070
+ )
3071
+ if (
3072
+ observed >= expires_at
3073
+ and not (
3074
+ request.get("status") == "approved"
3075
+ and request.get("decision") == "approve"
3076
+ and decided_at is not None
3077
+ and decided_at < expires_at
3078
+ )
3079
+ ):
3080
+ raise DriveGovernanceError(
3081
+ "approval_expired", "charter approval window has expired",
3082
+ )
3083
+ if request.get("status") != "approved" or request.get("decision") != "approve":
3084
+ raise DriveGovernanceError(
3085
+ "approval_not_approved", "charter transition is not approved",
3086
+ )
3087
+ if (
3088
+ request.get("action_digest") != binding.action_digest
3089
+ or request.get("scope_digest") != binding.scope_digest
3090
+ or _canonical(request.get("scope")) != _canonical(binding.scope)
3091
+ ):
3092
+ raise DriveGovernanceError(
3093
+ "approval_binding_mismatch",
3094
+ "approval does not bind the current immutable charter transition",
3095
+ )
3096
+ if (
3097
+ request.get("decided_by") != principal
3098
+ or not str(request.get("authority_evidence") or "").startswith(
3099
+ f"scoped_principal:{principal}:"
3100
+ )
3101
+ ):
3102
+ raise DriveGovernanceError(
3103
+ "owner_authority_mismatch",
3104
+ "approval decision does not match the server-derived owner authority",
3105
+ )
3106
+ return store._apply_transition(
3107
+ revision,
3108
+ transition=normalized,
3109
+ binding=binding,
3110
+ approval_request=request,
3111
+ operation_id=operation,
3112
+ principal_id=principal,
3113
+ require_no_active_charter=(self.mode == "bootstrap"),
3114
+ now=observed,
3115
+ )
3116
+
3117
+
3118
+ class DriveRanker:
3119
+ """Deterministically order goals that P3 has already admitted.
3120
+
3121
+ ``policy_decision_resolver`` must resolve durable decision references from
3122
+ ``CognitionSpineStore``. Caller-supplied booleans are never accepted as
3123
+ policy evidence. ``directive_manager`` is rechecked immediately before a
3124
+ ranking so a later boundary or global pause outranks an earlier P3 gate.
3125
+ """
3126
+
3127
+ def __init__(
3128
+ self,
3129
+ store: DriveGovernanceStore,
3130
+ *,
3131
+ policy_decision_resolver: Optional[
3132
+ Callable[[str], Optional[Mapping[str, Any]]]
3133
+ ],
3134
+ directive_manager: Any,
3135
+ charter_key: str = "default",
3136
+ ) -> None:
3137
+ self.store = store
3138
+ self._resolve_policy = policy_decision_resolver
3139
+ self._directives = directive_manager
3140
+ self.charter_key = str(charter_key or "default")
3141
+
3142
+ @staticmethod
3143
+ def _batch(
3144
+ *,
3145
+ status: str,
3146
+ mode: str,
3147
+ applied: bool,
3148
+ charter: Optional[CharterRevisionV1],
3149
+ goals: Sequence[GoalRankInputV1],
3150
+ suggested: Iterable[str] = (),
3151
+ effective: Optional[Iterable[str]] = None,
3152
+ held: Iterable[str] = (),
3153
+ results: Iterable[GoalRankResultV1] = (),
3154
+ now: datetime,
3155
+ ) -> RankingBatchV1:
3156
+ input_order = tuple(item.goal_id for item in goals)
3157
+ return RankingBatchV1(
3158
+ status=status,
3159
+ mode=mode,
3160
+ ranking_applied=applied,
3161
+ charter_revision_id=(charter.revision_id if charter else None),
3162
+ input_order=input_order,
3163
+ suggested_order=tuple(suggested),
3164
+ effective_order=(
3165
+ tuple(effective) if effective is not None else input_order
3166
+ ),
3167
+ held_goal_ids=tuple(held),
3168
+ results=tuple(results),
3169
+ generated_at=_iso(now),
3170
+ )
3171
+
3172
+ def _p3_gate_state(
3173
+ self, goal: GoalRankInputV1,
3174
+ ) -> tuple[str, tuple[str, ...]]:
3175
+ if self._resolve_policy is None or not goal.policy_decision_refs:
3176
+ return "p3_policy_unknown", ()
3177
+ stages: Dict[str, Mapping[str, Any]] = {}
3178
+ evidence: list[str] = []
3179
+ for reference in goal.policy_decision_refs:
3180
+ try:
3181
+ resolved = self._resolve_policy(reference)
3182
+ except Exception:
3183
+ return "p3_policy_unknown", ()
3184
+ if resolved is None or not isinstance(resolved, Mapping):
3185
+ return "p3_policy_unknown", ()
3186
+ payload = resolved.get("payload", resolved)
3187
+ if not isinstance(payload, Mapping):
3188
+ return "p3_policy_conflict", ()
3189
+ if (
3190
+ payload.get("decision_ref") != reference
3191
+ or payload.get("proposal_id") != goal.proposal_id
3192
+ or not isinstance(payload.get("allowed"), bool)
3193
+ ):
3194
+ return "p3_policy_conflict", ()
3195
+ stage = str(payload.get("stage") or "")
3196
+ if stage in stages:
3197
+ return "p3_policy_conflict", ()
3198
+ stages[stage] = payload
3199
+ try:
3200
+ evidence.extend(_refs(
3201
+ payload.get("evidence_refs") or (),
3202
+ field="policy evidence", maximum=30,
3203
+ ))
3204
+ except DriveGovernanceError:
3205
+ return "p3_policy_conflict", ()
3206
+ if any(stage not in stages for stage in _REQUIRED_P3_STAGES):
3207
+ return "p3_policy_unknown", tuple(dict.fromkeys(evidence))
3208
+ for stage in _REQUIRED_P3_STAGES:
3209
+ if not stages[stage]["allowed"]:
3210
+ return f"p3_{stage}_denied", tuple(dict.fromkeys(evidence))
3211
+ return "p3_eligible", tuple(dict.fromkeys(evidence))
3212
+
3213
+ def _directive_state(self, goal: GoalRankInputV1) -> tuple[str, str]:
3214
+ if self._directives is None:
3215
+ return "unknown", "directive_manager_unavailable"
3216
+ try:
3217
+ from apsimo.directives import Action
3218
+
3219
+ verdict = self._directives.check(Action(
3220
+ kind="project",
3221
+ text=f"{goal.title} {goal.objective_summary}",
3222
+ target=goal.title,
3223
+ high_risk=True,
3224
+ ))
3225
+ except Exception:
3226
+ return "unknown", "directive_check_failed"
3227
+ if bool(getattr(verdict, "allowed", False)):
3228
+ return "allowed", str(
3229
+ getattr(verdict, "reason", "boundary_allowed")
3230
+ )[:500]
3231
+ reason = str(getattr(verdict, "reason", "boundary_denied"))[:500]
3232
+ if reason == "global_pause_active":
3233
+ return "paused", reason
3234
+ return "denied", reason
3235
+
3236
+ @staticmethod
3237
+ def _held_result(
3238
+ goal: GoalRankInputV1,
3239
+ *,
3240
+ state: str,
3241
+ policy_evidence: Iterable[str] = (),
3242
+ charter: Optional[CharterRevisionV1] = None,
3243
+ ) -> GoalRankResultV1:
3244
+ scope = goal.scope
3245
+ if charter is not None:
3246
+ scope = _narrower_scope(scope, charter.scope)
3247
+ evidence = tuple(dict.fromkeys([
3248
+ *goal.evidence_refs, *policy_evidence,
3249
+ *(charter.evidence_refs if charter else ()),
3250
+ ]))[:30]
3251
+ return GoalRankResultV1(
3252
+ goal_id=goal.goal_id,
3253
+ proposal_id=goal.proposal_id,
3254
+ state=state,
3255
+ eligible=False,
3256
+ total_score=None,
3257
+ contributions=(),
3258
+ drive_states={},
3259
+ evidence_refs=evidence,
3260
+ policy_decision_refs=goal.policy_decision_refs,
3261
+ rationale_summary=(
3262
+ "Goal was not ranked because a required deterministic gate "
3263
+ f"reported {state}."
3264
+ ),
3265
+ scope=scope,
3266
+ )
3267
+
3268
+ def rank(
3269
+ self,
3270
+ goals: Sequence[GoalRankInputV1],
3271
+ *,
3272
+ mode: Optional[str] = None,
3273
+ now: Optional[datetime] = None,
3274
+ ) -> RankingBatchV1:
3275
+ selected_mode = _normalized_mode(mode)
3276
+ observed = _as_utc(now)
3277
+ bounded_goals = tuple(goals)
3278
+ if len({item.goal_id for item in bounded_goals}) != len(bounded_goals):
3279
+ raise DriveGovernanceError(
3280
+ "duplicate_goal", "ranking input repeats a goal id",
3281
+ )
3282
+ if selected_mode == "off":
3283
+ return self._batch(
3284
+ status="off", mode="off", applied=False, charter=None,
3285
+ goals=bounded_goals, now=observed,
3286
+ )
3287
+
3288
+ # Pause is checked even when charter state is missing or expired. P7
3289
+ # must never turn an unavailable ranking policy into a pause bypass.
3290
+ if self._directives is None:
3291
+ return self._batch(
3292
+ status="pause_state_unknown", mode=selected_mode,
3293
+ applied=False, charter=None, goals=bounded_goals,
3294
+ now=observed,
3295
+ )
3296
+ directive_states: Dict[str, tuple[str, str]] = {}
3297
+ directive_unknown = False
3298
+ globally_paused = False
3299
+ for goal in bounded_goals:
3300
+ directive_states[goal.goal_id] = self._directive_state(goal)
3301
+ if directive_states[goal.goal_id][0] == "unknown":
3302
+ directive_unknown = True
3303
+ if directive_states[goal.goal_id][0] == "paused":
3304
+ globally_paused = True
3305
+ if directive_unknown:
3306
+ return self._batch(
3307
+ status="pause_state_unknown", mode=selected_mode,
3308
+ applied=False, charter=None, goals=bounded_goals,
3309
+ now=observed,
3310
+ )
3311
+ if globally_paused:
3312
+ results = tuple(
3313
+ self._held_result(goal, state="global_pause_active")
3314
+ for goal in bounded_goals
3315
+ )
3316
+ return self._batch(
3317
+ status="global_pause_active", mode=selected_mode,
3318
+ applied=False, charter=None, goals=bounded_goals,
3319
+ effective=(), held=(item.goal_id for item in bounded_goals),
3320
+ results=results, now=observed,
3321
+ )
3322
+
3323
+ charter = self.store.active_revision(self.charter_key, now=observed)
3324
+ if charter is None:
3325
+ return self._batch(
3326
+ status="charter_unknown", mode=selected_mode, applied=False,
3327
+ charter=None, goals=bounded_goals, now=observed,
3328
+ )
3329
+ budget = charter.ranking_budget
3330
+ if len(bounded_goals) > budget.max_goals:
3331
+ return self._batch(
3332
+ status="goal_budget_exceeded", mode=selected_mode,
3333
+ applied=False, charter=charter, goals=bounded_goals,
3334
+ now=observed,
3335
+ )
3336
+ results: list[GoalRankResultV1] = []
3337
+ total_signals_used = 0
3338
+ weights = charter.weight_map()
3339
+ drives: Dict[str, Optional[DriveV1]] = {
3340
+ drive_id: self.store.get_drive(drive_id) for drive_id in weights
3341
+ }
3342
+ for goal in bounded_goals:
3343
+ gate_state, policy_evidence = self._p3_gate_state(goal)
3344
+ if gate_state != "p3_eligible":
3345
+ results.append(self._held_result(
3346
+ goal, state=gate_state,
3347
+ policy_evidence=policy_evidence, charter=charter,
3348
+ ))
3349
+ continue
3350
+ if directive_states[goal.goal_id][0] == "denied":
3351
+ results.append(self._held_result(
3352
+ goal,
3353
+ state="boundary_recheck_denied",
3354
+ policy_evidence=policy_evidence,
3355
+ charter=charter,
3356
+ ))
3357
+ continue
3358
+
3359
+ result_scope = _narrower_scope(goal.scope, charter.scope)
3360
+ evidence: list[str] = list(dict.fromkeys([
3361
+ *goal.evidence_refs, *policy_evidence, *charter.evidence_refs,
3362
+ ]))[:budget.max_evidence_refs_per_goal]
3363
+ drive_states: Dict[str, str] = {}
3364
+ contributions: list[DriveContributionV1] = []
3365
+ goal_signals = self.store.signals_for_goal(
3366
+ goal.goal_fingerprint, now=observed, include_expired=True,
3367
+ )
3368
+ grouped: Dict[str, list[DriveSignalV1]] = {}
3369
+ for item in goal_signals:
3370
+ grouped.setdefault(item.drive_id, []).append(item)
3371
+
3372
+ total_score = 0.0
3373
+ for drive_id, weight in sorted(weights.items()):
3374
+ drive = drives.get(drive_id)
3375
+ if drive is None:
3376
+ drive_state = "unknown"
3377
+ drive_states[drive_id] = drive_state
3378
+ contributions.append(DriveContributionV1(
3379
+ drive_id=drive_id, state=drive_state, weight=weight,
3380
+ raw_signal_value=0.0, mean_confidence=0.0,
3381
+ weighted_value=0.0, abs_budget=0.0,
3382
+ signal_refs=(), evidence_refs=(), rationale_summaries=(),
3383
+ ))
3384
+ continue
3385
+ effective_drive_state = drive.state_at(observed)
3386
+ if effective_drive_state != "enabled":
3387
+ drive_states[drive_id] = effective_drive_state
3388
+ contributions.append(DriveContributionV1(
3389
+ drive_id=drive_id, state=effective_drive_state,
3390
+ weight=weight, raw_signal_value=0.0,
3391
+ mean_confidence=0.0, weighted_value=0.0,
3392
+ abs_budget=drive.max_abs_contribution,
3393
+ signal_refs=(), evidence_refs=(), rationale_summaries=(),
3394
+ ))
3395
+ continue
3396
+ candidates = [
3397
+ item for item in grouped.get(drive_id, ())
3398
+ if item.state_at(observed) == "active"
3399
+ ]
3400
+ limit = min(
3401
+ drive.max_signals_per_goal,
3402
+ budget.max_signals_per_drive,
3403
+ max(0, budget.max_total_signals - total_signals_used),
3404
+ )
3405
+ selected = candidates[:limit]
3406
+ if not selected:
3407
+ observed_states = {
3408
+ item.state_at(observed)
3409
+ for item in grouped.get(drive_id, ())
3410
+ }
3411
+ if candidates and limit == 0:
3412
+ drive_state = "budget_exhausted"
3413
+ elif "unknown" in observed_states:
3414
+ drive_state = "unknown"
3415
+ elif "disabled" in observed_states:
3416
+ drive_state = "disabled"
3417
+ elif "expired" in observed_states:
3418
+ drive_state = "expired"
3419
+ else:
3420
+ drive_state = "unknown"
3421
+ drive_states[drive_id] = drive_state
3422
+ contributions.append(DriveContributionV1(
3423
+ drive_id=drive_id, state=drive_state, weight=weight,
3424
+ raw_signal_value=0.0, mean_confidence=0.0,
3425
+ weighted_value=0.0,
3426
+ abs_budget=drive.max_abs_contribution,
3427
+ signal_refs=(), evidence_refs=(), rationale_summaries=(),
3428
+ ))
3429
+ continue
3430
+ total_signals_used += len(selected)
3431
+ raw_value = sum(
3432
+ item.normalized_value for item in selected
3433
+ ) / len(selected)
3434
+ mean_confidence = sum(
3435
+ item.confidence for item in selected
3436
+ ) / len(selected)
3437
+ evidence_adjusted = sum(
3438
+ item.normalized_value * item.confidence for item in selected
3439
+ ) / len(selected)
3440
+ weighted = max(
3441
+ -drive.max_abs_contribution,
3442
+ min(drive.max_abs_contribution, evidence_adjusted * weight),
3443
+ )
3444
+ weighted = round(weighted, 8)
3445
+ total_score += weighted
3446
+ drive_states[drive_id] = "active"
3447
+ raw_contribution_evidence = tuple(dict.fromkeys(
3448
+ ref for item in selected for ref in item.evidence_refs
3449
+ ))
3450
+ visible_contribution_evidence: list[str] = []
3451
+ for reference in raw_contribution_evidence:
3452
+ if reference in evidence:
3453
+ visible_contribution_evidence.append(reference)
3454
+ elif len(evidence) < budget.max_evidence_refs_per_goal:
3455
+ evidence.append(reference)
3456
+ visible_contribution_evidence.append(reference)
3457
+ contribution_evidence = tuple(visible_contribution_evidence)
3458
+ for item in selected:
3459
+ result_scope = _narrower_scope(result_scope, item.scope)
3460
+ contributions.append(DriveContributionV1(
3461
+ drive_id=drive_id,
3462
+ state="active",
3463
+ weight=weight,
3464
+ raw_signal_value=round(raw_value, 8),
3465
+ mean_confidence=round(mean_confidence, 8),
3466
+ weighted_value=weighted,
3467
+ abs_budget=drive.max_abs_contribution,
3468
+ signal_refs=tuple(item.signal_id for item in selected),
3469
+ evidence_refs=contribution_evidence,
3470
+ rationale_summaries=tuple(
3471
+ item.rationale_summary for item in selected
3472
+ ),
3473
+ ))
3474
+ evidence_refs = tuple(evidence)
3475
+ results.append(GoalRankResultV1(
3476
+ goal_id=goal.goal_id,
3477
+ proposal_id=goal.proposal_id,
3478
+ state="ranked",
3479
+ eligible=True,
3480
+ total_score=round(max(-1.0, min(1.0, total_score)), 8),
3481
+ contributions=tuple(contributions),
3482
+ drive_states=drive_states,
3483
+ evidence_refs=evidence_refs,
3484
+ policy_decision_refs=goal.policy_decision_refs,
3485
+ rationale_summary=(
3486
+ "Weighted score uses only active, unexpired, "
3487
+ "evidence-referenced drive signals within the ratified "
3488
+ "charter budgets."
3489
+ ),
3490
+ scope=result_scope,
3491
+ ))
3492
+
3493
+ eligible = [item for item in results if item.eligible]
3494
+ ordered = sorted(
3495
+ eligible,
3496
+ key=lambda item: (
3497
+ -(item.total_score if item.total_score is not None else -1.0),
3498
+ item.goal_id,
3499
+ ),
3500
+ )
3501
+ suggested = tuple(item.goal_id for item in ordered)
3502
+ held = tuple(item.goal_id for item in results if not item.eligible)
3503
+ applied = selected_mode == "live"
3504
+ effective = suggested if applied else tuple(
3505
+ item.goal_id for item in bounded_goals
3506
+ )
3507
+ return self._batch(
3508
+ status="ranked" if applied else "shadow_ranked",
3509
+ mode=selected_mode,
3510
+ applied=applied,
3511
+ charter=charter,
3512
+ goals=bounded_goals,
3513
+ suggested=suggested,
3514
+ effective=effective,
3515
+ held=held,
3516
+ results=results,
3517
+ now=observed,
3518
+ )
3519
+
3520
+
3521
+ __all__ = [
3522
+ "CHARTER_TRANSITION_APPROVAL_PROJECTION_SCHEMA",
3523
+ "CharterAdmissionConstraintsV1", "CharterRevisionV1",
3524
+ "DriveContributionV1", "DriveGovernance",
3525
+ "DriveGovernanceError", "DriveGovernanceStore", "DriveRanker",
3526
+ "DriveSignalV1", "DriveV1", "GoalRankInputV1", "GoalRankResultV1",
3527
+ "RankingBatchV1", "RankingBudgetV1", "ScopeV1",
3528
+ "charter_transition_binding", "charter_transition_presentation",
3529
+ "charter_transition_subject", "drive_governance_mode",
3530
+ ]