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/genesis.py
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
"""Genesis block creation, Genesis admin capabilities, and single-chain enforcement.
|
|
2
|
+
|
|
3
|
+
The Genesis admin is a runtime claim — whoever submits the genesis block
|
|
4
|
+
becomes admin. Admin identity is tracked on-chain and transferable.
|
|
5
|
+
All admin actions are recorded on-chain and fully auditable.
|
|
6
|
+
|
|
7
|
+
Single-chain enforcement:
|
|
8
|
+
- Every block carries a network_id derived from the genesis block.
|
|
9
|
+
- Blocks from other chains (different network_id) are rejected.
|
|
10
|
+
- Genesis block creation is only offered when no existing network is found.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import hashlib
|
|
16
|
+
import json
|
|
17
|
+
import logging
|
|
18
|
+
import uuid
|
|
19
|
+
from dataclasses import dataclass, field
|
|
20
|
+
from datetime import datetime, timezone
|
|
21
|
+
from typing import Any, Callable, Optional
|
|
22
|
+
|
|
23
|
+
from .block import Block, build_merkle_root
|
|
24
|
+
from .transactions import Transaction, TxType
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class GenesisConfig:
|
|
31
|
+
"""Configuration for genesis block creation."""
|
|
32
|
+
|
|
33
|
+
network_name: str = "colony-federation"
|
|
34
|
+
genesis_colony_name: str = "genesis"
|
|
35
|
+
genesis_colony_id: str = "" # sha256(genesis_pubkey)
|
|
36
|
+
genesis_pubkey_hex: str = "" # 32-byte Ed25519 pubkey, hex
|
|
37
|
+
genesis_endpoint: str = ""
|
|
38
|
+
genesis_description: str = "Genesis colony — network founder"
|
|
39
|
+
block_interval_secs: int = 30
|
|
40
|
+
untrust_threshold: int = 3
|
|
41
|
+
untrust_window_days: int = 30
|
|
42
|
+
uptime_requirement_percent: float = 99.0
|
|
43
|
+
min_sentinels: int = 1
|
|
44
|
+
min_protocol_version: str = "1.0.0"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _derive_colony_id(public_key_hex: str) -> str:
|
|
48
|
+
"""Compute colony_id = sha256(public_key_bytes)."""
|
|
49
|
+
return hashlib.sha256(bytes.fromhex(public_key_hex)).hexdigest()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def create_genesis_block(
|
|
53
|
+
config: GenesisConfig,
|
|
54
|
+
sign_fn: Callable[[bytes], str],
|
|
55
|
+
producer_id: str = "genesis-sentinel",
|
|
56
|
+
) -> Block:
|
|
57
|
+
"""Create the genesis block with the founding colony's registration.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
config: Genesis configuration including the admin's public key.
|
|
61
|
+
sign_fn: Callable that signs bytes and returns hex signature.
|
|
62
|
+
producer_id: Sentinel ID producing the genesis block.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Fully constructed and signed genesis Block.
|
|
66
|
+
"""
|
|
67
|
+
ts = datetime.now(timezone.utc).isoformat()
|
|
68
|
+
|
|
69
|
+
# Derive colony_id if not provided
|
|
70
|
+
if not config.genesis_colony_id and config.genesis_pubkey_hex:
|
|
71
|
+
config.genesis_colony_id = _derive_colony_id(config.genesis_pubkey_hex)
|
|
72
|
+
|
|
73
|
+
# Build the genesis colony_register transaction
|
|
74
|
+
register_payload = {
|
|
75
|
+
"name": config.genesis_colony_name,
|
|
76
|
+
"public_key_hex": config.genesis_pubkey_hex,
|
|
77
|
+
"colony_id": config.genesis_colony_id,
|
|
78
|
+
"endpoint": config.genesis_endpoint,
|
|
79
|
+
"description": config.genesis_description,
|
|
80
|
+
"protocol_version": config.min_protocol_version,
|
|
81
|
+
"capabilities": ["task_delegation", "memory_sharing", "sentinel_relay"],
|
|
82
|
+
"genesis_admin": True,
|
|
83
|
+
"metadata": {},
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
register_tx = Transaction.create(
|
|
87
|
+
tx_type=TxType.COLONY_REGISTER,
|
|
88
|
+
from_colony_id=config.genesis_colony_id,
|
|
89
|
+
nonce=1,
|
|
90
|
+
payload=register_payload,
|
|
91
|
+
sign_fn=sign_fn,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
transactions = [register_tx]
|
|
95
|
+
tx_ids = [t.tx_id for t in transactions]
|
|
96
|
+
merkle_root = build_merkle_root(tx_ids)
|
|
97
|
+
|
|
98
|
+
# Compute network_id from genesis pubkey + name + timestamp
|
|
99
|
+
network_id_input = (
|
|
100
|
+
config.genesis_pubkey_hex + config.network_name + ts
|
|
101
|
+
).encode()
|
|
102
|
+
network_id = hashlib.sha256(network_id_input).hexdigest()
|
|
103
|
+
|
|
104
|
+
metadata: dict[str, Any] = {
|
|
105
|
+
"network_name": config.network_name,
|
|
106
|
+
"network_id": network_id,
|
|
107
|
+
"genesis_colony_id": config.genesis_colony_id,
|
|
108
|
+
"genesis_pubkey_hex": config.genesis_pubkey_hex,
|
|
109
|
+
"initial_config": {
|
|
110
|
+
"block_interval_secs": config.block_interval_secs,
|
|
111
|
+
"untrust_threshold": config.untrust_threshold,
|
|
112
|
+
"untrust_window_days": config.untrust_window_days,
|
|
113
|
+
"uptime_requirement_percent": config.uptime_requirement_percent,
|
|
114
|
+
"min_sentinels": config.min_sentinels,
|
|
115
|
+
"min_protocol_version": config.min_protocol_version,
|
|
116
|
+
},
|
|
117
|
+
"created_at": ts,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
block = Block(
|
|
121
|
+
index=0,
|
|
122
|
+
previous_hash="0" * 64,
|
|
123
|
+
timestamp=ts,
|
|
124
|
+
transactions=transactions,
|
|
125
|
+
merkle_root=merkle_root,
|
|
126
|
+
producer_id=producer_id,
|
|
127
|
+
signature="",
|
|
128
|
+
metadata=metadata,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Sign the block (excluding the signature field)
|
|
132
|
+
block_dict = block.to_dict()
|
|
133
|
+
block_dict.pop("signature", None)
|
|
134
|
+
canonical = json.dumps(block_dict, sort_keys=True, separators=(",", ":"))
|
|
135
|
+
block.signature = sign_fn(canonical.encode())
|
|
136
|
+
block._hash = "" # reset cached hash
|
|
137
|
+
|
|
138
|
+
return block
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class GenesisAdmin:
|
|
142
|
+
"""Genesis admin capability layer.
|
|
143
|
+
|
|
144
|
+
Provides helper methods for Genesis admin actions. Each action creates
|
|
145
|
+
and returns a Transaction that must be submitted to the chain.
|
|
146
|
+
All actions are recorded on-chain and fully auditable.
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
def __init__(
|
|
150
|
+
self,
|
|
151
|
+
genesis_colony_id: str,
|
|
152
|
+
sign_fn: Callable[[bytes], str],
|
|
153
|
+
get_nonce: Callable[[str], int],
|
|
154
|
+
) -> None:
|
|
155
|
+
self.genesis_colony_id = genesis_colony_id
|
|
156
|
+
self.sign_fn = sign_fn
|
|
157
|
+
self.get_nonce = get_nonce
|
|
158
|
+
|
|
159
|
+
def _next_nonce(self) -> int:
|
|
160
|
+
return self.get_nonce(self.genesis_colony_id) + 1
|
|
161
|
+
|
|
162
|
+
def suspend_colony(
|
|
163
|
+
self, target_colony_id: str, reason: str = "admin_action"
|
|
164
|
+
) -> Transaction:
|
|
165
|
+
"""Create a colony_suspend transaction as Genesis admin."""
|
|
166
|
+
return Transaction.create(
|
|
167
|
+
tx_type=TxType.COLONY_SUSPEND,
|
|
168
|
+
from_colony_id=self.genesis_colony_id,
|
|
169
|
+
nonce=self._next_nonce(),
|
|
170
|
+
payload={
|
|
171
|
+
"target_colony_id": target_colony_id,
|
|
172
|
+
"reason": reason,
|
|
173
|
+
"untrust_evidence_tx_ids": [],
|
|
174
|
+
"effective_height": 0,
|
|
175
|
+
"review_at_height": 0,
|
|
176
|
+
},
|
|
177
|
+
sign_fn=self.sign_fn,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
def reinstate_colony(
|
|
181
|
+
self,
|
|
182
|
+
target_colony_id: str,
|
|
183
|
+
conditions: str = "",
|
|
184
|
+
colony_acknowledgment: str = "",
|
|
185
|
+
) -> Transaction:
|
|
186
|
+
"""Create a colony_reinstate transaction as Genesis admin."""
|
|
187
|
+
return Transaction.create(
|
|
188
|
+
tx_type=TxType.COLONY_REINSTATE,
|
|
189
|
+
from_colony_id=self.genesis_colony_id,
|
|
190
|
+
nonce=self._next_nonce(),
|
|
191
|
+
payload={
|
|
192
|
+
"target_colony_id": target_colony_id,
|
|
193
|
+
"reinstated_by": "genesis",
|
|
194
|
+
"conditions": conditions,
|
|
195
|
+
"colony_acknowledgment": colony_acknowledgment,
|
|
196
|
+
},
|
|
197
|
+
sign_fn=self.sign_fn,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
def appoint_sentinel(
|
|
201
|
+
self,
|
|
202
|
+
sentinel_id: str,
|
|
203
|
+
colony_id: str,
|
|
204
|
+
host: str,
|
|
205
|
+
port: int,
|
|
206
|
+
public_key_hex: str,
|
|
207
|
+
) -> Transaction:
|
|
208
|
+
"""Appoint a Sentinel directly (genesis bootstrap, bypasses vote)."""
|
|
209
|
+
return Transaction.create(
|
|
210
|
+
tx_type=TxType.SENTINEL_REGISTER,
|
|
211
|
+
from_colony_id=self.genesis_colony_id,
|
|
212
|
+
nonce=self._next_nonce(),
|
|
213
|
+
payload={
|
|
214
|
+
"sentinel_id": sentinel_id,
|
|
215
|
+
"colony_id": colony_id,
|
|
216
|
+
"host": host,
|
|
217
|
+
"port": port,
|
|
218
|
+
"public_key_hex": public_key_hex,
|
|
219
|
+
"uptime_proof": {
|
|
220
|
+
"period_days": 30,
|
|
221
|
+
"uptime_percent": 100.0,
|
|
222
|
+
"attestation_tx_ids": [],
|
|
223
|
+
},
|
|
224
|
+
"approver_signatures": [],
|
|
225
|
+
"genesis_approved": True,
|
|
226
|
+
},
|
|
227
|
+
sign_fn=self.sign_fn,
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
def remove_sentinel(
|
|
231
|
+
self, sentinel_id: str, reason: str = "admin_action"
|
|
232
|
+
) -> Transaction:
|
|
233
|
+
"""Forcibly remove a Sentinel (policy violation)."""
|
|
234
|
+
return Transaction.create(
|
|
235
|
+
tx_type=TxType.SENTINEL_DEREGISTER,
|
|
236
|
+
from_colony_id=self.genesis_colony_id,
|
|
237
|
+
nonce=self._next_nonce(),
|
|
238
|
+
payload={
|
|
239
|
+
"sentinel_id": sentinel_id,
|
|
240
|
+
"reason": reason,
|
|
241
|
+
"successor_sentinel_id": None,
|
|
242
|
+
},
|
|
243
|
+
sign_fn=self.sign_fn,
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
def force_release_name(self, name: str) -> Transaction:
|
|
247
|
+
"""Force-release a squatted name."""
|
|
248
|
+
return Transaction.create(
|
|
249
|
+
tx_type=TxType.COLONY_RELEASE_NAME,
|
|
250
|
+
from_colony_id=self.genesis_colony_id,
|
|
251
|
+
nonce=self._next_nonce(),
|
|
252
|
+
payload={"name": name, "reason": "admin_force_release"},
|
|
253
|
+
sign_fn=self.sign_fn,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
def propose_protocol_upgrade(
|
|
257
|
+
self,
|
|
258
|
+
title: str,
|
|
259
|
+
description: str,
|
|
260
|
+
changes: dict[str, Any],
|
|
261
|
+
activation_height: int,
|
|
262
|
+
sentinel_votes: list[dict] | None = None,
|
|
263
|
+
) -> Transaction:
|
|
264
|
+
"""Propose a protocol upgrade. Sentinels vote via signed payloads."""
|
|
265
|
+
return Transaction.create(
|
|
266
|
+
tx_type=TxType.PROTOCOL_UPGRADE,
|
|
267
|
+
from_colony_id=self.genesis_colony_id,
|
|
268
|
+
nonce=self._next_nonce(),
|
|
269
|
+
payload={
|
|
270
|
+
"upgrade_id": str(uuid.uuid4()),
|
|
271
|
+
"title": title[:128],
|
|
272
|
+
"description": description[:4096],
|
|
273
|
+
"spec_url": "",
|
|
274
|
+
"changes": changes,
|
|
275
|
+
"activation_height": activation_height,
|
|
276
|
+
"votes": sentinel_votes or [],
|
|
277
|
+
},
|
|
278
|
+
sign_fn=self.sign_fn,
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
def broadcast_announcement(self, message: str) -> Transaction:
|
|
282
|
+
"""Submit a network-wide broadcast announcement via a no-op protocol_upgrade."""
|
|
283
|
+
return Transaction.create(
|
|
284
|
+
tx_type=TxType.PROTOCOL_UPGRADE,
|
|
285
|
+
from_colony_id=self.genesis_colony_id,
|
|
286
|
+
nonce=self._next_nonce(),
|
|
287
|
+
payload={
|
|
288
|
+
"upgrade_id": str(uuid.uuid4()),
|
|
289
|
+
"title": "broadcast",
|
|
290
|
+
"description": message[:4096],
|
|
291
|
+
"spec_url": "",
|
|
292
|
+
"changes": {},
|
|
293
|
+
"activation_height": 999_999_999, # never activates
|
|
294
|
+
"votes": [],
|
|
295
|
+
"broadcast": True,
|
|
296
|
+
},
|
|
297
|
+
sign_fn=self.sign_fn,
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
def vote_strip_genesis_admin(self, sentinel_id: str) -> dict[str, Any]:
|
|
301
|
+
"""Return a signed vote dict for unanimous Sentinel strip of Genesis admin.
|
|
302
|
+
|
|
303
|
+
This is NOT a standalone transaction — it produces a vote entry that must
|
|
304
|
+
be aggregated with all other Sentinel votes before submitting the
|
|
305
|
+
strip_genesis_admin protocol_upgrade transaction.
|
|
306
|
+
|
|
307
|
+
The caller submits:
|
|
308
|
+
GenesisAdmin.build_strip_genesis_admin(votes)
|
|
309
|
+
once all Sentinels have voted.
|
|
310
|
+
"""
|
|
311
|
+
payload = {
|
|
312
|
+
"sentinel_id": sentinel_id,
|
|
313
|
+
"action": "strip_genesis_admin",
|
|
314
|
+
"vote": "yes",
|
|
315
|
+
}
|
|
316
|
+
import json as _json
|
|
317
|
+
canonical = _json.dumps(payload, sort_keys=True, separators=(",", ":"))
|
|
318
|
+
signature = self.sign_fn(canonical.encode())
|
|
319
|
+
return {"sentinel_id": sentinel_id, "vote": "yes", "signature": signature}
|
|
320
|
+
|
|
321
|
+
def build_strip_genesis_admin(self, sentinel_votes: list[dict]) -> Transaction:
|
|
322
|
+
"""Build the co-signed strip_genesis_admin protocol_upgrade transaction.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
sentinel_votes: List of vote dicts from vote_strip_genesis_admin(),
|
|
326
|
+
one per active Sentinel. All must be "yes" for the state machine
|
|
327
|
+
to accept the strip.
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
A PROTOCOL_UPGRADE transaction with title="strip_genesis_admin".
|
|
331
|
+
"""
|
|
332
|
+
return Transaction.create(
|
|
333
|
+
tx_type=TxType.PROTOCOL_UPGRADE,
|
|
334
|
+
from_colony_id=self.genesis_colony_id,
|
|
335
|
+
nonce=self._next_nonce(),
|
|
336
|
+
payload={
|
|
337
|
+
"upgrade_id": str(uuid.uuid4()),
|
|
338
|
+
"title": "strip_genesis_admin",
|
|
339
|
+
"description": "Unanimous Sentinel vote to strip Genesis admin",
|
|
340
|
+
"spec_url": "",
|
|
341
|
+
"changes": {},
|
|
342
|
+
"activation_height": 0,
|
|
343
|
+
"votes": sentinel_votes,
|
|
344
|
+
},
|
|
345
|
+
sign_fn=self.sign_fn,
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
def transfer_admin(
|
|
349
|
+
self, new_admin_colony_id: str, new_admin_pubkey_hex: str
|
|
350
|
+
) -> Transaction:
|
|
351
|
+
"""Transfer Genesis admin role to another colony.
|
|
352
|
+
|
|
353
|
+
Records a protocol_upgrade that notes the new admin.
|
|
354
|
+
The actual transfer is enforced by chain state machine when processed.
|
|
355
|
+
"""
|
|
356
|
+
return Transaction.create(
|
|
357
|
+
tx_type=TxType.PROTOCOL_UPGRADE,
|
|
358
|
+
from_colony_id=self.genesis_colony_id,
|
|
359
|
+
nonce=self._next_nonce(),
|
|
360
|
+
payload={
|
|
361
|
+
"upgrade_id": str(uuid.uuid4()),
|
|
362
|
+
"title": "transfer_genesis_admin",
|
|
363
|
+
"description": f"Transfer genesis admin to {new_admin_colony_id}",
|
|
364
|
+
"spec_url": "",
|
|
365
|
+
"changes": {
|
|
366
|
+
"new_genesis_admin_id": new_admin_colony_id,
|
|
367
|
+
"new_genesis_admin_pubkey": new_admin_pubkey_hex,
|
|
368
|
+
},
|
|
369
|
+
"activation_height": 0,
|
|
370
|
+
"votes": [],
|
|
371
|
+
},
|
|
372
|
+
sign_fn=self.sign_fn,
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
# ---------------------------------------------------------------------------
|
|
377
|
+
# Single-chain enforcement
|
|
378
|
+
# ---------------------------------------------------------------------------
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
class ChainForkError(Exception):
|
|
382
|
+
"""Raised when a block from a different chain (different network_id) is received."""
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def validate_chain_origin(
|
|
386
|
+
local_network_id: str,
|
|
387
|
+
received_block: Block,
|
|
388
|
+
sender_node_id: Optional[str] = None,
|
|
389
|
+
) -> None:
|
|
390
|
+
"""Validate that a received block belongs to the local network.
|
|
391
|
+
|
|
392
|
+
Requirements:
|
|
393
|
+
- MUST reject blocks with network_id != local_network_id.
|
|
394
|
+
- MUST reject genesis blocks with index=0 if a genesis block already exists
|
|
395
|
+
(caller must check this condition before calling).
|
|
396
|
+
- MUST log rejected blocks with sender_node_id for audit.
|
|
397
|
+
|
|
398
|
+
Raises:
|
|
399
|
+
ChainForkError: If the block belongs to a different network.
|
|
400
|
+
"""
|
|
401
|
+
received_network_id = received_block.metadata.get("network_id")
|
|
402
|
+
if received_network_id != local_network_id:
|
|
403
|
+
logger.warning(
|
|
404
|
+
"CHAIN FORK REJECTED: block network_id=%r does not match local=%r sender=%s",
|
|
405
|
+
received_network_id,
|
|
406
|
+
local_network_id,
|
|
407
|
+
sender_node_id or "unknown",
|
|
408
|
+
)
|
|
409
|
+
raise ChainForkError(
|
|
410
|
+
f"Block network_id {received_network_id!r} does not match "
|
|
411
|
+
f"local network_id {local_network_id!r}. "
|
|
412
|
+
"This block is from a different chain and has been rejected."
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def should_offer_genesis_creation(sentinels_found: list) -> bool:
|
|
417
|
+
"""Return True only when zero Sentinels were found during discovery.
|
|
418
|
+
|
|
419
|
+
This is the first-install detection gate. Genesis block creation is ONLY
|
|
420
|
+
offered once, ever, when no existing network is present.
|
|
421
|
+
|
|
422
|
+
Args:
|
|
423
|
+
sentinels_found: List of Sentinel addresses discovered during the
|
|
424
|
+
mDNS / SWIM / relay discovery phase.
|
|
425
|
+
|
|
426
|
+
Returns:
|
|
427
|
+
True if no existing network was found and genesis creation is appropriate.
|
|
428
|
+
"""
|
|
429
|
+
return len(sentinels_found) == 0
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def extract_network_id(genesis_block: Block) -> str:
|
|
433
|
+
"""Extract and validate the network_id from a genesis block.
|
|
434
|
+
|
|
435
|
+
Raises:
|
|
436
|
+
ValueError: If the genesis block has no network_id in its metadata.
|
|
437
|
+
"""
|
|
438
|
+
network_id = genesis_block.metadata.get("network_id")
|
|
439
|
+
if not network_id:
|
|
440
|
+
raise ValueError(
|
|
441
|
+
"Genesis block has no network_id in metadata — cannot join this chain."
|
|
442
|
+
)
|
|
443
|
+
return network_id
|