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
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
"""Durable P8 visibility envelopes with authorized bounded projection.
|
|
2
|
+
|
|
3
|
+
The ledger persists :class:`FactVisibilityV1` records, never fact content. A
|
|
4
|
+
producer must append a :class:`FactCandidateV1`, which lets this boundary
|
|
5
|
+
recompute the exact UTF-8 content digest before storing the envelope. A fact
|
|
6
|
+
reference is an immutable event identity: exact replay is a no-op and any
|
|
7
|
+
changed content, audience, freshness, evidence, or confidence is a conflict.
|
|
8
|
+
|
|
9
|
+
This module has no server startup hook. ``open_visibility_envelope_store()``
|
|
10
|
+
defaults disabled so merely importing or probing the P8 candidate creates no
|
|
11
|
+
directory or database.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
from datetime import datetime, timezone
|
|
18
|
+
import hashlib
|
|
19
|
+
import json
|
|
20
|
+
import math
|
|
21
|
+
import os
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
import re
|
|
24
|
+
import sqlite3
|
|
25
|
+
import threading
|
|
26
|
+
from typing import Any, Optional
|
|
27
|
+
|
|
28
|
+
from apsimo.tom.visibility import (
|
|
29
|
+
FactCandidateV1,
|
|
30
|
+
FactVisibilityV1,
|
|
31
|
+
ViewerContextV1,
|
|
32
|
+
content_digest,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
SCHEMA_VERSION = 1
|
|
37
|
+
MAX_PROJECTED_ENVELOPES = 64
|
|
38
|
+
MAX_ENVELOPES_SCANNED = 2_048
|
|
39
|
+
|
|
40
|
+
_REF_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.:@/+\-]{0,191}$")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class VisibilityEnvelopeConflictError(ValueError):
|
|
44
|
+
"""A fact reference replay changed its immutable visibility envelope."""
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _canonical(value: Any) -> str:
|
|
48
|
+
return json.dumps(
|
|
49
|
+
value,
|
|
50
|
+
ensure_ascii=True,
|
|
51
|
+
separators=(",", ":"),
|
|
52
|
+
sort_keys=True,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _digest(value: Any) -> str:
|
|
57
|
+
return hashlib.sha256(_canonical(value).encode("utf-8")).hexdigest()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _iso(value: datetime | str, *, field: str) -> str:
|
|
61
|
+
if isinstance(value, datetime):
|
|
62
|
+
parsed = value
|
|
63
|
+
else:
|
|
64
|
+
try:
|
|
65
|
+
parsed = datetime.fromisoformat(str(value).replace("Z", "+00:00"))
|
|
66
|
+
except (TypeError, ValueError) as exc:
|
|
67
|
+
raise ValueError(f"{field} must be an ISO-8601 timestamp") from exc
|
|
68
|
+
if parsed.tzinfo is None:
|
|
69
|
+
raise ValueError(f"{field} must include a timezone")
|
|
70
|
+
return parsed.astimezone(timezone.utc).isoformat()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@dataclass(frozen=True, slots=True)
|
|
74
|
+
class VisibilityEnvelopeAppendV1:
|
|
75
|
+
envelope: FactVisibilityV1
|
|
76
|
+
sequence: int
|
|
77
|
+
appended: bool
|
|
78
|
+
replayed: bool
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass(frozen=True, slots=True)
|
|
82
|
+
class VisibilityEnvelopeProjectionV1:
|
|
83
|
+
envelopes: tuple[FactVisibilityV1, ...]
|
|
84
|
+
viewer_attested: bool
|
|
85
|
+
corrupt_count: int
|
|
86
|
+
truncated: bool
|
|
87
|
+
viewer_digest: str
|
|
88
|
+
audit_digest: str
|
|
89
|
+
schema_version: int = SCHEMA_VERSION
|
|
90
|
+
|
|
91
|
+
def public(self) -> dict[str, Any]:
|
|
92
|
+
return {
|
|
93
|
+
"schema_version": self.schema_version,
|
|
94
|
+
"envelopes": [envelope.public() for envelope in self.envelopes],
|
|
95
|
+
"viewer_attested": self.viewer_attested,
|
|
96
|
+
"corrupt_count": self.corrupt_count,
|
|
97
|
+
"truncated": self.truncated,
|
|
98
|
+
"viewer_digest": self.viewer_digest,
|
|
99
|
+
"audit_digest": self.audit_digest,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class FactVisibilityStore:
|
|
104
|
+
"""Append-only SQLite ledger of verified visibility envelopes."""
|
|
105
|
+
|
|
106
|
+
def __init__(self, db_path: str | os.PathLike[str] = ":memory:") -> None:
|
|
107
|
+
self.path = str(db_path)
|
|
108
|
+
if self.path != ":memory:":
|
|
109
|
+
path = Path(self.path)
|
|
110
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
111
|
+
if not path.exists():
|
|
112
|
+
path.touch(mode=0o600)
|
|
113
|
+
else:
|
|
114
|
+
os.chmod(path, 0o600)
|
|
115
|
+
self._lock = threading.RLock()
|
|
116
|
+
self._conn = sqlite3.connect(
|
|
117
|
+
self.path, check_same_thread=False, timeout=30.0)
|
|
118
|
+
self._conn.row_factory = sqlite3.Row
|
|
119
|
+
self._conn.execute("PRAGMA busy_timeout=30000")
|
|
120
|
+
self._conn.execute("PRAGMA recursive_triggers=ON")
|
|
121
|
+
self._conn.execute("PRAGMA journal_mode=WAL")
|
|
122
|
+
self._conn.execute("PRAGMA synchronous=FULL")
|
|
123
|
+
self._conn.executescript(
|
|
124
|
+
"""
|
|
125
|
+
CREATE TABLE IF NOT EXISTS fact_visibility_envelopes (
|
|
126
|
+
seq INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
127
|
+
fact_ref TEXT NOT NULL UNIQUE,
|
|
128
|
+
visibility_digest TEXT NOT NULL UNIQUE,
|
|
129
|
+
content_digest TEXT NOT NULL,
|
|
130
|
+
source_ref TEXT NOT NULL,
|
|
131
|
+
subject_person_id TEXT NOT NULL,
|
|
132
|
+
viewer_scope TEXT NOT NULL,
|
|
133
|
+
shareability TEXT NOT NULL,
|
|
134
|
+
confidence REAL NOT NULL,
|
|
135
|
+
observed_at TEXT NOT NULL,
|
|
136
|
+
fresh_until TEXT NOT NULL,
|
|
137
|
+
payload_json TEXT NOT NULL,
|
|
138
|
+
stored_at TEXT NOT NULL
|
|
139
|
+
);
|
|
140
|
+
CREATE INDEX IF NOT EXISTS idx_fact_visibility_viewer_fresh
|
|
141
|
+
ON fact_visibility_envelopes(viewer_scope,fresh_until);
|
|
142
|
+
CREATE INDEX IF NOT EXISTS idx_fact_visibility_subject_fresh
|
|
143
|
+
ON fact_visibility_envelopes(subject_person_id,fresh_until);
|
|
144
|
+
CREATE INDEX IF NOT EXISTS idx_fact_visibility_shareability_fresh
|
|
145
|
+
ON fact_visibility_envelopes(shareability,fresh_until);
|
|
146
|
+
CREATE INDEX IF NOT EXISTS idx_fact_visibility_fresh
|
|
147
|
+
ON fact_visibility_envelopes(fresh_until);
|
|
148
|
+
CREATE TRIGGER IF NOT EXISTS fact_visibility_no_update
|
|
149
|
+
BEFORE UPDATE ON fact_visibility_envelopes BEGIN
|
|
150
|
+
SELECT RAISE(ABORT, 'fact visibility is append-only');
|
|
151
|
+
END;
|
|
152
|
+
CREATE TRIGGER IF NOT EXISTS fact_visibility_no_delete
|
|
153
|
+
BEFORE DELETE ON fact_visibility_envelopes BEGIN
|
|
154
|
+
SELECT RAISE(ABORT, 'fact visibility is append-only');
|
|
155
|
+
END;
|
|
156
|
+
CREATE TRIGGER IF NOT EXISTS fact_visibility_no_replace
|
|
157
|
+
BEFORE INSERT ON fact_visibility_envelopes
|
|
158
|
+
WHEN EXISTS (
|
|
159
|
+
SELECT 1 FROM fact_visibility_envelopes
|
|
160
|
+
WHERE seq=NEW.seq
|
|
161
|
+
OR fact_ref=NEW.fact_ref
|
|
162
|
+
OR visibility_digest=NEW.visibility_digest
|
|
163
|
+
) BEGIN
|
|
164
|
+
SELECT RAISE(ABORT, 'fact visibility is append-only');
|
|
165
|
+
END;
|
|
166
|
+
"""
|
|
167
|
+
)
|
|
168
|
+
self._conn.commit()
|
|
169
|
+
if self.path != ":memory:":
|
|
170
|
+
os.chmod(self.path, 0o600)
|
|
171
|
+
|
|
172
|
+
@staticmethod
|
|
173
|
+
def _decode(row: sqlite3.Row) -> FactVisibilityV1:
|
|
174
|
+
try:
|
|
175
|
+
payload = json.loads(row["payload_json"])
|
|
176
|
+
except (TypeError, ValueError) as exc:
|
|
177
|
+
raise ValueError("visibility envelope payload is unreadable") from exc
|
|
178
|
+
envelope = FactVisibilityV1(**payload)
|
|
179
|
+
indexed = {
|
|
180
|
+
"fact_ref": str(row["fact_ref"]),
|
|
181
|
+
"visibility_digest": str(row["visibility_digest"]),
|
|
182
|
+
"content_digest": str(row["content_digest"]),
|
|
183
|
+
"source_ref": str(row["source_ref"]),
|
|
184
|
+
"subject_person_id": str(row["subject_person_id"]),
|
|
185
|
+
"viewer_scope": str(row["viewer_scope"]),
|
|
186
|
+
"shareability": str(row["shareability"]),
|
|
187
|
+
"confidence": float(row["confidence"]),
|
|
188
|
+
"observed_at": str(row["observed_at"]),
|
|
189
|
+
"fresh_until": str(row["fresh_until"]),
|
|
190
|
+
}
|
|
191
|
+
expected = {
|
|
192
|
+
"fact_ref": envelope.fact_ref,
|
|
193
|
+
"visibility_digest": envelope.audit_digest,
|
|
194
|
+
"content_digest": envelope.content_digest,
|
|
195
|
+
"source_ref": envelope.source_ref,
|
|
196
|
+
"subject_person_id": envelope.subject_person_id,
|
|
197
|
+
"viewer_scope": envelope.viewer_scope,
|
|
198
|
+
"shareability": envelope.shareability,
|
|
199
|
+
"confidence": envelope.confidence,
|
|
200
|
+
"observed_at": envelope.observed_at,
|
|
201
|
+
"fresh_until": envelope.fresh_until,
|
|
202
|
+
}
|
|
203
|
+
if indexed != expected:
|
|
204
|
+
raise ValueError("visibility envelope digest/index mismatch")
|
|
205
|
+
return envelope
|
|
206
|
+
|
|
207
|
+
def append(self, candidate: FactCandidateV1) -> VisibilityEnvelopeAppendV1:
|
|
208
|
+
"""Verify content binding, then append or exactly replay one envelope."""
|
|
209
|
+
|
|
210
|
+
if not isinstance(candidate, FactCandidateV1):
|
|
211
|
+
raise ValueError("FactVisibilityStore accepts FactCandidateV1 only")
|
|
212
|
+
envelope = candidate.visibility
|
|
213
|
+
if content_digest(candidate.content) != envelope.content_digest:
|
|
214
|
+
raise ValueError("fact content digest does not match visibility")
|
|
215
|
+
with self._lock:
|
|
216
|
+
self._conn.execute("BEGIN IMMEDIATE")
|
|
217
|
+
try:
|
|
218
|
+
row = self._conn.execute(
|
|
219
|
+
"SELECT * FROM fact_visibility_envelopes WHERE fact_ref=?",
|
|
220
|
+
(envelope.fact_ref,),
|
|
221
|
+
).fetchone()
|
|
222
|
+
if row is not None:
|
|
223
|
+
saved = self._decode(row)
|
|
224
|
+
if saved.audit_digest == envelope.audit_digest:
|
|
225
|
+
self._conn.commit()
|
|
226
|
+
return VisibilityEnvelopeAppendV1(
|
|
227
|
+
envelope=saved,
|
|
228
|
+
sequence=int(row["seq"]),
|
|
229
|
+
appended=False,
|
|
230
|
+
replayed=True,
|
|
231
|
+
)
|
|
232
|
+
raise VisibilityEnvelopeConflictError(
|
|
233
|
+
"fact reference changed its immutable visibility envelope")
|
|
234
|
+
cursor = self._conn.execute(
|
|
235
|
+
"INSERT INTO fact_visibility_envelopes "
|
|
236
|
+
"(fact_ref,visibility_digest,content_digest,source_ref,"
|
|
237
|
+
"subject_person_id,viewer_scope,shareability,confidence,"
|
|
238
|
+
"observed_at,fresh_until,payload_json,stored_at) "
|
|
239
|
+
"VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",
|
|
240
|
+
(
|
|
241
|
+
envelope.fact_ref,
|
|
242
|
+
envelope.audit_digest,
|
|
243
|
+
envelope.content_digest,
|
|
244
|
+
envelope.source_ref,
|
|
245
|
+
envelope.subject_person_id,
|
|
246
|
+
envelope.viewer_scope,
|
|
247
|
+
envelope.shareability,
|
|
248
|
+
envelope.confidence,
|
|
249
|
+
envelope.observed_at,
|
|
250
|
+
envelope.fresh_until,
|
|
251
|
+
_canonical(envelope.public()),
|
|
252
|
+
datetime.now(timezone.utc).isoformat(),
|
|
253
|
+
),
|
|
254
|
+
)
|
|
255
|
+
self._conn.commit()
|
|
256
|
+
return VisibilityEnvelopeAppendV1(
|
|
257
|
+
envelope=envelope,
|
|
258
|
+
sequence=int(cursor.lastrowid),
|
|
259
|
+
appended=True,
|
|
260
|
+
replayed=False,
|
|
261
|
+
)
|
|
262
|
+
except Exception:
|
|
263
|
+
self._conn.rollback()
|
|
264
|
+
raise
|
|
265
|
+
|
|
266
|
+
def get(self, fact_ref: str) -> Optional[FactVisibilityV1]:
|
|
267
|
+
normalized = str(fact_ref or "").strip()
|
|
268
|
+
if not _REF_RE.fullmatch(normalized):
|
|
269
|
+
raise ValueError("fact_ref is not a bounded opaque reference")
|
|
270
|
+
with self._lock:
|
|
271
|
+
row = self._conn.execute(
|
|
272
|
+
"SELECT * FROM fact_visibility_envelopes WHERE fact_ref=?",
|
|
273
|
+
(normalized,),
|
|
274
|
+
).fetchone()
|
|
275
|
+
return self._decode(row) if row is not None else None
|
|
276
|
+
|
|
277
|
+
def envelope_count(self) -> int:
|
|
278
|
+
with self._lock:
|
|
279
|
+
row = self._conn.execute(
|
|
280
|
+
"SELECT COUNT(*) AS n FROM fact_visibility_envelopes"
|
|
281
|
+
).fetchone()
|
|
282
|
+
return int(row["n"] if row else 0)
|
|
283
|
+
|
|
284
|
+
@staticmethod
|
|
285
|
+
def _viewer_scopes(viewer: ViewerContextV1) -> tuple[str, ...]:
|
|
286
|
+
scopes = {"public", f"person:{viewer.viewer_person_id}"}
|
|
287
|
+
if "global" in viewer.audiences:
|
|
288
|
+
scopes.add("audience:global")
|
|
289
|
+
if "shared" in viewer.audiences:
|
|
290
|
+
scopes.add("audience:shared")
|
|
291
|
+
if viewer.conversation_scope:
|
|
292
|
+
scopes.add(f"conversation:{viewer.conversation_scope}")
|
|
293
|
+
return tuple(sorted(scopes))
|
|
294
|
+
|
|
295
|
+
def project_authorized(
|
|
296
|
+
self,
|
|
297
|
+
viewer: ViewerContextV1,
|
|
298
|
+
*,
|
|
299
|
+
now: datetime | str,
|
|
300
|
+
min_confidence: float = 0.0,
|
|
301
|
+
max_envelopes: int = 24,
|
|
302
|
+
) -> VisibilityEnvelopeProjectionV1:
|
|
303
|
+
"""Return only fresh envelopes authorized for the exact viewer."""
|
|
304
|
+
|
|
305
|
+
if not isinstance(viewer, ViewerContextV1):
|
|
306
|
+
raise ValueError("viewer must be ViewerContextV1")
|
|
307
|
+
if not 1 <= int(max_envelopes) <= MAX_PROJECTED_ENVELOPES:
|
|
308
|
+
raise ValueError("max_envelopes is outside bounded projection range")
|
|
309
|
+
floor = float(min_confidence)
|
|
310
|
+
if not math.isfinite(floor) or not 0.0 <= floor <= 1.0:
|
|
311
|
+
raise ValueError("min_confidence must be between zero and one")
|
|
312
|
+
observed = _iso(now, field="now")
|
|
313
|
+
|
|
314
|
+
if not viewer.attested or not viewer.viewer_person_id:
|
|
315
|
+
payload = {
|
|
316
|
+
"schema_version": SCHEMA_VERSION,
|
|
317
|
+
"viewer_digest": viewer.audit_digest,
|
|
318
|
+
"viewer_attested": False,
|
|
319
|
+
"envelope_digests": (),
|
|
320
|
+
"corrupt_count": 0,
|
|
321
|
+
"truncated": False,
|
|
322
|
+
"now": observed,
|
|
323
|
+
"min_confidence": floor,
|
|
324
|
+
"max_envelopes": int(max_envelopes),
|
|
325
|
+
}
|
|
326
|
+
return VisibilityEnvelopeProjectionV1(
|
|
327
|
+
envelopes=(),
|
|
328
|
+
viewer_attested=False,
|
|
329
|
+
corrupt_count=0,
|
|
330
|
+
truncated=False,
|
|
331
|
+
viewer_digest=viewer.audit_digest,
|
|
332
|
+
audit_digest=_digest(payload),
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
params: list[Any] = [observed, observed, floor]
|
|
336
|
+
where = (
|
|
337
|
+
"observed_at<=? AND fresh_until>? AND confidence>=?"
|
|
338
|
+
)
|
|
339
|
+
if viewer.viewer_person_id != viewer.owner_person_id:
|
|
340
|
+
scopes = self._viewer_scopes(viewer)
|
|
341
|
+
where += " AND viewer_scope IN (%s)" % ",".join(
|
|
342
|
+
"?" for _ in scopes)
|
|
343
|
+
params.extend(scopes)
|
|
344
|
+
params.append(MAX_ENVELOPES_SCANNED + 1)
|
|
345
|
+
with self._lock:
|
|
346
|
+
rows = self._conn.execute(
|
|
347
|
+
"SELECT * FROM fact_visibility_envelopes WHERE " + where
|
|
348
|
+
+ " ORDER BY confidence DESC,observed_at DESC,fact_ref ASC LIMIT ?",
|
|
349
|
+
tuple(params),
|
|
350
|
+
).fetchall()
|
|
351
|
+
|
|
352
|
+
scan_truncated = len(rows) > MAX_ENVELOPES_SCANNED
|
|
353
|
+
rows = rows[:MAX_ENVELOPES_SCANNED]
|
|
354
|
+
eligible: list[FactVisibilityV1] = []
|
|
355
|
+
corrupt_count = 0
|
|
356
|
+
for row in rows:
|
|
357
|
+
try:
|
|
358
|
+
envelope = self._decode(row)
|
|
359
|
+
decision = envelope.decision(
|
|
360
|
+
viewer, now=observed, min_confidence=floor)
|
|
361
|
+
except Exception:
|
|
362
|
+
corrupt_count += 1
|
|
363
|
+
continue
|
|
364
|
+
if decision.allowed:
|
|
365
|
+
eligible.append(envelope)
|
|
366
|
+
|
|
367
|
+
truncated = scan_truncated or len(eligible) > int(max_envelopes)
|
|
368
|
+
projected = tuple(eligible[:int(max_envelopes)])
|
|
369
|
+
payload = {
|
|
370
|
+
"schema_version": SCHEMA_VERSION,
|
|
371
|
+
"viewer_digest": viewer.audit_digest,
|
|
372
|
+
"viewer_attested": True,
|
|
373
|
+
"envelope_digests": tuple(
|
|
374
|
+
envelope.audit_digest for envelope in projected),
|
|
375
|
+
"corrupt_count": corrupt_count,
|
|
376
|
+
"truncated": truncated,
|
|
377
|
+
"now": observed,
|
|
378
|
+
"min_confidence": floor,
|
|
379
|
+
"max_envelopes": int(max_envelopes),
|
|
380
|
+
}
|
|
381
|
+
return VisibilityEnvelopeProjectionV1(
|
|
382
|
+
envelopes=projected,
|
|
383
|
+
viewer_attested=True,
|
|
384
|
+
corrupt_count=corrupt_count,
|
|
385
|
+
truncated=truncated,
|
|
386
|
+
viewer_digest=viewer.audit_digest,
|
|
387
|
+
audit_digest=_digest(payload),
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
def close(self) -> None:
|
|
391
|
+
with self._lock:
|
|
392
|
+
try:
|
|
393
|
+
self._conn.close()
|
|
394
|
+
except Exception:
|
|
395
|
+
pass
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def open_visibility_envelope_store(
|
|
399
|
+
db_path: str | os.PathLike[str],
|
|
400
|
+
*,
|
|
401
|
+
enabled: bool = False,
|
|
402
|
+
) -> Optional[FactVisibilityStore]:
|
|
403
|
+
"""Create the store only after a caller explicitly enables this slice."""
|
|
404
|
+
|
|
405
|
+
return FactVisibilityStore(db_path) if enabled is True else None
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
__all__ = [
|
|
409
|
+
"FactVisibilityStore",
|
|
410
|
+
"VisibilityEnvelopeAppendV1",
|
|
411
|
+
"VisibilityEnvelopeConflictError",
|
|
412
|
+
"VisibilityEnvelopeProjectionV1",
|
|
413
|
+
"open_visibility_envelope_store",
|
|
414
|
+
]
|
apsimo/tools/__init__.py
ADDED
|
File without changes
|