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