topos-node 1.3.29__tar.gz → 1.3.31__tar.gz
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.
- {topos_node-1.3.29/topos_node.egg-info → topos_node-1.3.31}/PKG-INFO +1 -1
- {topos_node-1.3.29 → topos_node-1.3.31}/pyproject.toml +1 -1
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/__version__.py +2 -2
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/signal.py +50 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/config/model_packs.py +6 -1
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/derivation.py +55 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/aspirations.goals.yaml +2 -2
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/health.mental.yaml +3 -3
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/places.mobility.yaml +2 -2
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/work.career.yaml +4 -4
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/surfaces.py +189 -3
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/template.py +2 -2
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/writer.py +31 -13
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/maintenance.py +7 -2
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/facts/reads.py +3 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/protocol/handled_message_types.json +3 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/protocol/narrowing_vocabulary.json +1 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/facts_direct.py +18 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/game_layer.py +17 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/narrowing.py +1 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/packet_resolution.py +17 -2
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/pipeline.py +2 -1
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/retrieval.py +38 -1
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/adapters/sqlite/stores.py +41 -9
- topos_node-1.3.31/topos/storage/db/migrations/conflict_provenance_v1.py +35 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/registry.py +5 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/registry_checksums.json +1 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/upgrades/manifests.json +12 -0
- {topos_node-1.3.29 → topos_node-1.3.31/topos_node.egg-info}/PKG-INFO +1 -1
- {topos_node-1.3.29 → topos_node-1.3.31}/topos_node.egg-info/SOURCES.txt +1 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/LICENSE +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/MANIFEST.in +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/README.md +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/setup.cfg +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/shared/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/shared/filtering.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/shared/schema_registry.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/tests/test_active_database_binding.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/tests/test_active_ingestion_binding.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/tests/test_extensions.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/tests/test_gate_leg_hermeticity.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/tests/test_llm_integrations_storage.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/tests/test_local_gate_composition.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/tests/test_owner_database_hermeticity.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/tests/test_prewarm_first_run.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/tests/test_profile_hygiene.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/tests/test_profiles.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/tests/test_protocol_handled_types.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/tests/test_query_field_contract.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/tests/test_system_computer_name.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/analytics/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/analytics/duckdb_adapter.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/analytics/messenger_communities.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/analytics/messenger_graph.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/analytics/messenger_labels.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/analytics/profiles.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/analytics/query_engine.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/analytics/raw_queries.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/analytics.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/app_registry.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/backup.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/community_naming_config.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/compute_remote.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/conversation_context.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/data_commit.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/data_explorer_table_prefs.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/database_explorer.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/db.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/device.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/engine_run.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/enrichment.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/enrichment_lab.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/facts_llm_config.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/filter_lab.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/health.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/home_chat.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/ingestion_api.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/ingestion_compat.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/ingestion_sources.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/intelligence_lifecycle.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/llm.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/local_mcp.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/messenger_analytics.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/privacy_disclose.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/query_api.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/runtime_bootstrap.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/sanitization_ollama_config.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/shell.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/signal_extraction_config.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/source_install.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/source_scrub.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/sources.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/sources_overview.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/sync.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/tool_index.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/ui_config.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/uma_data.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/upgrades.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/usage.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/api/user_identity.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/app.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/auth.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/canonicalization/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/canonicalization/declared_field_map.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/canonicalization/mappers/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/canonicalization/mappers/base.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/canonicalization/mappers/browser_activity_mapper.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/canonicalization/mappers/chatgpt_mapper.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/canonicalization/mappers/demo_mappers.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/canonicalization/mappers/documents_mapper.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/canonicalization/mappers/github_activity_mapper.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/canonicalization/mappers/google_calendar_mapper.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/canonicalization/mappers/grok_mapper.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/canonicalization/mappers/messenger_mapper.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/canonicalization/models.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/canonicalization/resolver.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/cli/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/cli/__main__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/cli/assets/topos_blk_rounded.png +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/cli/assets/topos_white.png +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/cli/commands.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/cli/profile_cmd.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/cli/reprocess_cmd.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/cli/setup_models_cmd.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/cli/tray.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/config/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/config/conversation_context_llm.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/config/facts_llm.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/config/local_model_builds.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/config/node_function_providers.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/config/sanitization_ollama.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/config/settings.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/config/signal_extraction.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/config/uvicorn_logging.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/contacts/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/contacts/identity.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/control_plane_client.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/api_models.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/connection_resilience.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/db_health.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/device_helpers.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/errors.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/events.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/common.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/complexity.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/config.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/contacts_import.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/database_explorer.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/device.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/enrichment.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/enrichment_lab.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/filter_lab.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/graph_query.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/home_chat.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/ingest.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/messages.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/messenger_analytics.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/query.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/registry.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/routines.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/signal_features.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/sources.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/timeline_daily.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/tool_index.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/handlers/uma.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/logging.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/metrics.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/routine_access.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/startup_banner.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/state.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/table_layers.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/core/types.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/data_explorer_row_delete.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/data_explorer_table_prefs.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/data_explorer_tables.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/disclosure/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/disclosure/canonical_writer.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/disclosure/content_policy.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/disclosure/field_registry.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/disclosure/privacy_layer.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/disclosure/tier.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/backends/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/backends/base.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/backends/generative_prompts.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/backends/generative_response.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/backends/huggingface.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/backends/ollama.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/backends/openai.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/backends/openai_compatible.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/backends/redpill.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/backends/stub.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/client.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/disk_space.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/engine.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/intake.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/memory_utils.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/model_cache.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/ollama_install.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/ollama_pull.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/ollama_setup_guidance.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/pipeline_memory.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/queue_manager.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/registration.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/result_formatter.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/router.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/scoped_token.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/tasks.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/torch_runtime.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/transport.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/usage_guard.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/usage_observation.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/engine/validator.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/catalog.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/derivation_recovery.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/derived_tables.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/job_readiness.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/job_writer.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/base.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/_batch_limits.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/_engine_runner.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/attention_triage_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/availability_scores_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/brief_fallback.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/complexity_snapshot_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/derivation_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/dimension_summary_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/embeddings_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/emo_27_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/entities_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/fact_extraction_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/goal_extraction_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/pii_redaction_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/relationship_edges_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/sentiment_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/statistics_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/timeline_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/topic_clusters_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/canonical/topics_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/raw/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/raw/attachments_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/raw/language_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/raw/time_normalization_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/jobs/raw/tool_calls_job.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/model_overrides.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/models/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/models/manager.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/models/mvp_defaults.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/models/registry.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/models/versioning.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/orchestrator.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/pipeline_activity.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/processor.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/progress_bar.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/registry_contract.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/signal_derivation_config.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment/source_overrides.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment_lab/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment_lab/bundles.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment_lab/model_resolve.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment_lab/schema.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment_lab/service.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment_lab/store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/enrichment_lab/worker.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/evals/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/evals/enrichment_eval.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/extensions.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/complexity/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/complexity/canonical.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/complexity/engine.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/complexity/entropy.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/complexity/focus.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/complexity/graph_metrics.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/complexity/influence.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/complexity/projection.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/complexity/snapshots.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/complexity/store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/complexity/topic_merge.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/complexity/topics.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/complexity/topics_daily.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/complexity/volatility.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/_scales.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/admin.legal.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/behavior.habits.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/behavior.preferences.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/beliefs.civic.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/beliefs.spiritual.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/communication.style.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/community.membership.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/craft.tooling.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/expertise.knowledge.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/finances.economics.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/health.lifestyle.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/health.physical.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/household.pets.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/identity.core.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/interests.taste.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/life.events.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/narrative.self.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/personality.traits.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/possessions.assets.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/relationships.social.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/values.motivation.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/vocab/dispositions.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/vocab/expertise.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/vocab/habits.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/vocab/interests.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/vocab/preferences.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/vocab/stances.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/vocab/tools.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/vocab/values.yaml +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/candidates.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/guard.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/packs.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/prefilter.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/registry.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/report_card.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/router.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/synthesize.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/verify.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/affinity.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/affinity_owner.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/affinity_quality.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/community_names.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/community_naming.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/consolidation.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/context_vectors.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/cypher.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/declared_mappings.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/dossier.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/edges.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/fact_materializer.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/graph_enrichers.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/graph_refresh.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/graph_search.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/linking.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/reads.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/rebuild_subprocess.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/entities/resolver.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/facts/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/facts/extract.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/facts/llm_extract.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/facts/store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/facts/verdicts.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/fit/evaluator.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/fit/opportunity_types.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/lifecycle/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/lifecycle/blackhole.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/lifecycle/blackhole_guard.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/lifecycle/blackhole_llm.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/lifecycle/blackhole_rebuild.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/lifecycle/derived_scrub.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/lifecycle/exclusions.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/lifecycle/gc.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/provenance/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/provenance/posture.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/provenance/roles.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/brief_canonical_loader.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/brief_ontology.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/brief_renderer.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/brief_schemas.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/chunking.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/cluster_labels.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/conversation_context.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/data_health.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/definitions/brief_ontologies.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/definitions/intentions.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/definitions/interests.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/definitions/memory.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/definitions/places.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/definitions/profile.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/definitions/relationships.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/definitions/resources.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/definitions/schema/dimension_definition.schema.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/definitions/time.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/definitions/wellbeing.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/definitions/work.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/derived_spec.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/dimension_briefs.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/dimension_definition_loader.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/dimension_profiles.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/dimension_registry.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/embed_context.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/extraction/artifact_router.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/extraction/artifact_store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/extraction/rule_extractors.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/graph_sanitize.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/hybrid_search.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/incremental_clustering.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/model_recommendations.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/query_embed_cache.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/schemas.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/service.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/signal_object_store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/source_hydration.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/structured_signal.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/tool_index.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/topic_clustering.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/typed_stores/aggregates.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/typed_stores/commitments.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/typed_stores/rhythm.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/typed_stores/scope_materializer.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/vector_codec.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/vector_math.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/signal/vector_settings.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/stats/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/stats/definitions.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/stats/engine.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/stats/fold.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/stats/insights.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/timeline_projection.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/timeline_rollup.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/triage/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/triage/badges.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/triage/daily.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/triage/dashboard.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/triage/instruments.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/triage/intents.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/features/triage/readiness.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/filter_lab/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/filter_lab/bundles.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/filter_lab/schema.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/filter_lab/service.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/filter_lab/store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/filter_lab/worker.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/home_chat/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/home_chat/schema.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/home_chat/store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/hosted_pool_lease.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/canonical_pipeline.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/checkpoints/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/checkpoints/checkpoint_store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/checkpoints/sqlite_checkpoint_store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/inbox_crypto.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/inbox_drain.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/ingest_helpers.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/jobs.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/journal_location_fanout.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/journal_time_log_normalize.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/local_sync.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/log_preview.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/manager.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/parser.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/parsers/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/parsers/base.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/parsers/browser_parser.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/parsers/calendar_parser.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/parsers/chatgpt_conversation_flattener.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/parsers/chatgpt_parser.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/parsers/demo_file_parsers.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/parsers/documents_parser.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/parsers/github_activity_parser.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/parsers/google_calendar_parser.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/parsers/grok_parser.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/parsers/messenger_parser.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/parsers/voxterm_parser.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/progress.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/reprocess.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/sources/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/sources/base.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/sources/calendar.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/sources/chatgpt.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/sources/contact_importers.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/sources/grok.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/sources/imessage_reader.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/sources/signal_export_parser.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/sources/signal_reader.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/state_machine.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/triggers/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/triggers/file_trigger.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/triggers/sqlite_trigger.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/usage_inbox_dedupe.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/validation/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/validation/base.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/validation/schema_registry.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/ingestion/validation/schema_validator.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/lineage/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/lineage/provenance.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/lineage/tracker.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/llm_integrations_storage.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/mcp_stdio_proxy.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/observability/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/observability/alerts.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/observability/metrics.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/observability/tracing.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/openai_client.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/pipeline/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/pipeline/audit.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/pipeline/envelope.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/pipeline/job_runner.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/pipeline/job_store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/pipeline/stages.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/pipeline/stub_enqueue.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/profiles.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/projections/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/projections/vector_index/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/projections/vector_index/base.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/projections/vector_index/builders.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/projections/vector_index/health_checks.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/protocol/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/protocol/query_field_contract.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/audit.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/cohort_resolvers.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/ddr.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/disclosure.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/entity_window.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/exclusion.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/fingerprint.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/grant_cache.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/inference.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/intent.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/manifest.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/manifest_validation.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/minimizer.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/negotiation.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/planner.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/runtime.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/scope_arbiter.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/scope_classifier.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/scope_head.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/scope_registry.json +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/scope_registry_loader.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/scope_shadow.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/session.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/session_utils.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/source_generation.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/truth_facts.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/truth_prompts.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/turn_classifier.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/types.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/verify.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/query/verify_modes.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/rate_limit.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/routines/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/routines/schema.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/routines/store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/runtime_housekeeping.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/runtime_shutdown.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/runtime_update.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sanitization/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sanitization/nsfw_classifier.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sanitization/ollama_transforms.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sanitization/prewarm.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sanitization/privacy_filter.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/scope_resolution.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/services/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/services/container.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/services/embeddings/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/services/embeddings/base.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/services/embeddings/local.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/services/embeddings/remote.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/services/interfaces.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/services/llm/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/services/llm/base.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/services/llm/openai.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/services/local.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/services/postgres.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sources/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sources/bundled_canonical_triples.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sources/canonical_signal_defaults.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sources/declared_field_map_spec.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sources/definitions.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sources/install_service.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sources/registry.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sources/runtime_install.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sources/scrub_attribution.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sources/scrub_service.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/startup_banner.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/adapters/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/adapters/factory.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/adapters/fakes.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/adapters/postgres/stores.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/adapters/protocols.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/adapters/sqlite/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/adapters/sqlite/vector_search.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/canonical/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/canonical/activity_tables.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/canonical/ai_chat/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/canonical/ai_chat/canonicalizer.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/canonical/ai_chat/mapper.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/canonical/ai_chat/model.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/canonical/ai_chat/tables.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/canonical/calendar_contacts_tables.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/canonical/canonical_store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/canonical/conversations_tables.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/canonical/journal_repair.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/canonical/mapping_store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/canonical/postgres.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/client.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/connection_tuning.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/activity_events_content_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/actor_role_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/affinity_pair_labels_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/attention_triage_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/attention_triage_v2.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/backup.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/calendar_events_scheduling_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/canonical_address_book_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/canonical_disclosure_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/canonical_nsfw_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/community_names_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/complexity_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/conversation_context_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/derivation_factory_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/derivation_ledger_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/derivation_provenance_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/documents_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/enrichment_record_progress_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/enrichment_spec_version_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/entity_affinity_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/entity_blackhole_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/entity_context_vectors_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/entity_context_vectors_v2.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/entity_edges_validity_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/entity_mentions_authored_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/entity_review_candidate_bar_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/entity_review_dedup_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/entity_review_provenance_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/episodes_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/extraction_artifacts.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/journal_entries_duration_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/journal_entries_ends_at_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/journal_entries_people_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/journal_entries_place_name_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/journal_entries_starts_at_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/journal_origin_dimension_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/message_emotions_role_backfill_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/message_emotions_role_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/pack_registry_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/pipeline_jobs_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/query_artifacts_duration_ms_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/remediation_person_model.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/retire_url_classification_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/scope_source_generation.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/signal_dimension_backfill_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/signal_dimension_harness.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/signal_objects.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/signal_objects_period_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/signal_objects_updated_by_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/signal_summaries_drop_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/stage9_column_renames.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/vector_storage_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/vector_storage_v2.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/vector_storage_v3.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/vector_storage_v4.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/wiki_clusters_v2.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/wiki_entities_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/wiki_entity_review_v2.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/wiki_facts_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/wiki_lifecycle_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/wiki_mvp_phase0.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/wiki_mvp_phase1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/wiki_mvp_phase4_messages_cutover.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/wiki_mvp_phase5_topic_clusters.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/wiki_mvp_phase6_dimension_briefs.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/wiki_mvp_query_quality.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/wiki_mvp_topic_clusters_coordination.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/wiki_stats_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/migrations/wiki_timeline_v1.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/paths.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/postgres.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/schema.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/schema_probe.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/storage_breakdown.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/db/write_gate.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/enrichment/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/enrichment/canonical_enrichment_store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/enrichment/raw_enrichment_store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/normalized/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/normalized/normalized_store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/oplog/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/oplog/decision.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/oplog/oplog_store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/oplog/postgres.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/person/identity_resolver.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/projections/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/projections/index_ops_store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/projections/vector_index_store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/raw/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/raw/browser_flat_tables.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/raw/file_store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/raw/raw_store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/raw/raw_tables_manager.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/raw/sqlite_raw_store.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/security/encryption.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/signal_identity.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/source_settings.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/storage/user_identity.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sync/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sync/client.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/sync_handlers.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/testing/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/testing/lifespan.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/uma_contact_enrichment.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/uma_filters.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/uma_resource_id.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/uma_rpt.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/upgrades/__init__.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/upgrades/runner.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/utils/base_object.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos/websocket_client.py +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos_node.egg-info/dependency_links.txt +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos_node.egg-info/entry_points.txt +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos_node.egg-info/requires.txt +0 -0
- {topos_node-1.3.29 → topos_node-1.3.31}/topos_node.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "topos-node"
|
|
7
|
-
version = "1.3.
|
|
7
|
+
version = "1.3.31"
|
|
8
8
|
description = "Topos personal AI engine (FastAPI): local data, sync, control plane WebSocket client"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -1156,3 +1156,53 @@ async def put_community_name_route(
|
|
|
1156
1156
|
)
|
|
1157
1157
|
commit_connection(conn)
|
|
1158
1158
|
return {"community_id": community_id, "name": name, "members": len(rows)}
|
|
1159
|
+
|
|
1160
|
+
|
|
1161
|
+
@router.get("/derivation/schema")
|
|
1162
|
+
async def get_derivation_schema(_api_key: str = Depends(require_api_key)):
|
|
1163
|
+
"""Per-predicate field schemas for the Fact Editor (W4.6)."""
|
|
1164
|
+
from ..features.derivation.surfaces import predicate_schemas
|
|
1165
|
+
|
|
1166
|
+
return {"predicates": predicate_schemas(_entities_conn())}
|
|
1167
|
+
|
|
1168
|
+
|
|
1169
|
+
@router.post("/facts/conflicts/promote")
|
|
1170
|
+
async def post_conflict_promotion(
|
|
1171
|
+
conflict_id: str = Body(...),
|
|
1172
|
+
subject_entity_id: str = Body(""),
|
|
1173
|
+
new_person_name: str = Body(""),
|
|
1174
|
+
to_owner: bool = Body(False),
|
|
1175
|
+
value: Any = Body(None),
|
|
1176
|
+
_api_key: str = Depends(require_api_key),
|
|
1177
|
+
):
|
|
1178
|
+
"""Edit & add a quarantined extraction: the owner supplies the identity the
|
|
1179
|
+
machine refused to guess; ledgered as gold (W4.6)."""
|
|
1180
|
+
from ..features.derivation.surfaces import promote_conflict
|
|
1181
|
+
|
|
1182
|
+
try:
|
|
1183
|
+
return promote_conflict(_entities_conn(), conflict_id,
|
|
1184
|
+
subject_entity_id=subject_entity_id,
|
|
1185
|
+
new_person_name=new_person_name,
|
|
1186
|
+
value=value, to_owner=to_owner)
|
|
1187
|
+
except ValueError as exc:
|
|
1188
|
+
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
1189
|
+
|
|
1190
|
+
|
|
1191
|
+
@router.post("/facts/{object_id}/revise")
|
|
1192
|
+
async def post_fact_revision(
|
|
1193
|
+
object_id: str,
|
|
1194
|
+
value: Any = Body(None),
|
|
1195
|
+
subject_entity_id: str = Body(""),
|
|
1196
|
+
evidence_date: str = Body(""),
|
|
1197
|
+
asserted_by: str = Body(""),
|
|
1198
|
+
_api_key: str = Depends(require_api_key),
|
|
1199
|
+
):
|
|
1200
|
+
"""Owner revision of a live pack fact: field/subject/date, never its kind (W4.6)."""
|
|
1201
|
+
from ..features.derivation.surfaces import revise_fact
|
|
1202
|
+
|
|
1203
|
+
try:
|
|
1204
|
+
return revise_fact(_entities_conn(), object_id, value=value,
|
|
1205
|
+
subject_entity_id=subject_entity_id,
|
|
1206
|
+
evidence_date=evidence_date, asserted_by=asserted_by)
|
|
1207
|
+
except ValueError as exc:
|
|
1208
|
+
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
@@ -271,7 +271,12 @@ def _as_binding(raw: Any) -> Optional[Dict[str, str]]:
|
|
|
271
271
|
def _local_model_present(binding: Mapping[str, str], installed_local_models: Optional[Any]) -> bool:
|
|
272
272
|
if installed_local_models is None:
|
|
273
273
|
return True
|
|
274
|
-
|
|
274
|
+
provider = str(binding.get("provider") or "").strip().lower()
|
|
275
|
+
# Horos is local but not an Ollama tag; `default` must not look like a
|
|
276
|
+
# missing download. Mirrors control_plane.model_pack_resolution.
|
|
277
|
+
if provider == SCOPE_HEAD_PROVIDER:
|
|
278
|
+
return True
|
|
279
|
+
if provider not in LOCAL_PROVIDERS:
|
|
275
280
|
return True
|
|
276
281
|
installed = {str(name or "").strip().lower() for name in installed_local_models}
|
|
277
282
|
wanted = str(binding.get("model") or "").strip().lower()
|
|
@@ -119,3 +119,58 @@ async def handle_run_pack_backfill(message):
|
|
|
119
119
|
return {"id": req_id, "status": "error", "error": str(exc)}
|
|
120
120
|
except Exception as exc: # noqa: BLE001
|
|
121
121
|
return {"id": req_id, "status": "error", "error": str(exc)}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@handles("get_derivation_schema")
|
|
125
|
+
async def handle_get_derivation_schema(message):
|
|
126
|
+
req_id = message.get("id")
|
|
127
|
+
conn = hub.get_db_connection()
|
|
128
|
+
if not conn:
|
|
129
|
+
return {"id": req_id, "status": "error", "error": "Database not available"}
|
|
130
|
+
try:
|
|
131
|
+
from ...features.derivation.surfaces import predicate_schemas
|
|
132
|
+
return {"id": req_id, "status": "ok",
|
|
133
|
+
"payload": {"status": "ok", "predicates": predicate_schemas(conn)}}
|
|
134
|
+
except Exception as exc: # noqa: BLE001
|
|
135
|
+
return {"id": req_id, "status": "error", "error": str(exc)}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@handles("promote_fact_conflict")
|
|
139
|
+
async def handle_promote_fact_conflict(message):
|
|
140
|
+
req_id = message.get("id")
|
|
141
|
+
conn = hub.get_db_connection()
|
|
142
|
+
if not conn:
|
|
143
|
+
return {"id": req_id, "status": "error", "error": "Database not available"}
|
|
144
|
+
p = message.get("payload") or {}
|
|
145
|
+
try:
|
|
146
|
+
from ...features.derivation.surfaces import promote_conflict
|
|
147
|
+
out = promote_conflict(conn, str(p.get("conflict_id") or ""),
|
|
148
|
+
subject_entity_id=str(p.get("subject_entity_id") or ""),
|
|
149
|
+
new_person_name=str(p.get("new_person_name") or ""),
|
|
150
|
+
value=p.get("value"), to_owner=bool(p.get("to_owner")))
|
|
151
|
+
return {"id": req_id, "status": "ok", "payload": {"status": "ok", **out}}
|
|
152
|
+
except ValueError as exc:
|
|
153
|
+
return {"id": req_id, "status": "error", "error": str(exc)}
|
|
154
|
+
except Exception as exc: # noqa: BLE001
|
|
155
|
+
return {"id": req_id, "status": "error", "error": str(exc)}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@handles("revise_pack_fact")
|
|
159
|
+
async def handle_revise_pack_fact(message):
|
|
160
|
+
req_id = message.get("id")
|
|
161
|
+
conn = hub.get_db_connection()
|
|
162
|
+
if not conn:
|
|
163
|
+
return {"id": req_id, "status": "error", "error": "Database not available"}
|
|
164
|
+
p = message.get("payload") or {}
|
|
165
|
+
try:
|
|
166
|
+
from ...features.derivation.surfaces import revise_fact
|
|
167
|
+
out = revise_fact(conn, str(p.get("object_id") or ""),
|
|
168
|
+
value=p.get("value"),
|
|
169
|
+
subject_entity_id=str(p.get("subject_entity_id") or ""),
|
|
170
|
+
evidence_date=str(p.get("evidence_date") or ""),
|
|
171
|
+
asserted_by=str(p.get("asserted_by") or ""))
|
|
172
|
+
return {"id": req_id, "status": "ok", "payload": {"status": "ok", **out}}
|
|
173
|
+
except ValueError as exc:
|
|
174
|
+
return {"id": req_id, "status": "error", "error": str(exc)}
|
|
175
|
+
except Exception as exc: # noqa: BLE001
|
|
176
|
+
return {"id": req_id, "status": "error", "error": str(exc)}
|
|
@@ -73,8 +73,8 @@ guidance:
|
|
|
73
73
|
- "Authored-only: an assigned OKR is work context, not a personal goal, unless the owner adopts it in their own words."
|
|
74
74
|
- "Idle wishes ('would love to someday') are aspirations, never goals — the horizon field is load-bearing."
|
|
75
75
|
- "v0.2.4 A goal is STATED INTENT in the owner's own words ('Goal:', 'I want to', 'I will').
|
|
76
|
-
Wry observations, jokes and family lore ('
|
|
77
|
-
|
|
76
|
+
Wry observations, jokes and family lore ('guess the family streak continues through me
|
|
77
|
+
') are never goals — if the owner would be surprised to see it on their goal list,
|
|
78
78
|
extract nothing."
|
|
79
79
|
- "v0.2.4 goal_ref is a NAME (a few words), not a sentence — a goal_ref longer than ~8 words
|
|
80
80
|
means the goal was never really named; prefer the Goal: header's own phrasing."
|
{topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/health.mental.yaml
RENAMED
|
@@ -31,7 +31,7 @@ predicates:
|
|
|
31
31
|
v0.2.4 — a state report is a FELT-STATE statement about how the owner is/was
|
|
32
32
|
("I am exhausted", "slept 8 hours, wild dreams", "so nervous with the talk").
|
|
33
33
|
An intention, aspiration, reflection or observation is NOT a state, whatever
|
|
34
|
-
dimension it brushes: "I need to be
|
|
34
|
+
dimension it brushes: "I need to be around more ambitious builders" is a
|
|
35
35
|
want, not an energy report; "the talk motivated me to write" is a reflection,
|
|
36
36
|
not a focus report. If the words don't describe how the owner FEELS or FELT,
|
|
37
37
|
extract nothing.
|
|
@@ -70,9 +70,9 @@ eval:
|
|
|
70
70
|
- {text: "Third week straight of terrible sleep, I'm running on fumes", role: authored,
|
|
71
71
|
expect: [{predicate: mind.self_reported_state, value: {dimension: sleep_quality}}]}
|
|
72
72
|
negative_controls:
|
|
73
|
-
- {text: "I need to be
|
|
73
|
+
- {text: "I need to be around more ambitious builders. To go out of my way to find them.", role: authored,
|
|
74
74
|
expect_not: [{predicate: mind.self_reported_state}], note: "v0.2.4 measured junk: a want is not an energy state"}
|
|
75
|
-
- {text: "The
|
|
75
|
+
- {text: "The workshop at the end inspired me to draft my own essay on collaboration tools.", role: authored,
|
|
76
76
|
expect_not: [{predicate: mind.self_reported_state}], note: "v0.2.4 measured junk: a reflection is not a focus state"}
|
|
77
77
|
- {text: "Podcast episode about burnout culture in tech", role: ambient, expect: []}
|
|
78
78
|
- {text: "My brother finally started therapy, proud of him", role: authored, expect: [], note: "third party"}
|
{topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/places.mobility.yaml
RENAMED
|
@@ -81,8 +81,8 @@ decisions:
|
|
|
81
81
|
- >
|
|
82
82
|
2026-08-26 (W5 gate, measured): role_policy tightened to authored_addressed —
|
|
83
83
|
with ambient/observed allowed, OTHER PEOPLE'S messages became owner place-ties
|
|
84
|
-
("I am once again at
|
|
85
|
-
a friend's
|
|
84
|
+
("I am once again at the Harbor Cafe" from a friend -> owner workplace_location;
|
|
85
|
+
a friend's parking find -> owner tie to that city). 4/5 sampled accepts
|
|
86
86
|
were junk, dominated by this leak. Location-bearing ambient signals return
|
|
87
87
|
via the no-LLM synthesizer lane (timestamps/geo), never via LLM reading of
|
|
88
88
|
others' words.
|
{topos_node-1.3.29 → topos_node-1.3.31}/topos/features/derivation/bundled_packs/work.career.yaml
RENAMED
|
@@ -117,12 +117,12 @@ eval:
|
|
|
117
117
|
expect: [{predicate: work.project, value: {status: paused}}]}
|
|
118
118
|
negative_controls:
|
|
119
119
|
- {text: "Sounds like Dana's team is hiring three more", role: authored, expect: [], note: "other team's news"}
|
|
120
|
-
- {text: "I applied to
|
|
121
|
-
- {text: "I applied to the
|
|
120
|
+
- {text: "I applied to Meridian's open role today", role: authored, expect: [], note: "v0.2.2 measured junk: applied is NOT hired"}
|
|
121
|
+
- {text: "I applied to the Horizon Startup Fund", role: authored, expect: [], note: "v0.2.2 measured junk: applying for funding is NOT started_venture"}
|
|
122
122
|
- {text: "I filed for unemployment.", role: authored, expect: [{predicate: work.employment_shape, value: between_roles}],
|
|
123
123
|
expect_not: [{predicate: work.career_event}], note: "v0.2.2: shape yes, event no"}
|
|
124
|
-
- {text: "I took the
|
|
125
|
-
- {text: "All day with
|
|
124
|
+
- {text: "I took the practice aptitude test again. Scored a 32.", role: authored, expect: [], note: "v0.2.2 measured junk: a test score is not an award"}
|
|
125
|
+
- {text: "All day with Harbor Ventures.", role: authored, expect_not: [{predicate: work.employer}], note: "v0.2.2 measured junk: co-presence is not employment"}
|
|
126
126
|
- {text: "(newsletter: 'The 2026 layoff wave continues')", role: ambient, expect: []}
|
|
127
127
|
calibration: {min_conf_for_assert: 0.65, ece_max: 0.15}
|
|
128
128
|
|
|
@@ -70,11 +70,16 @@ def set_pack_enabled(conn: sqlite3.Connection, pack_id: str, enabled: bool) -> b
|
|
|
70
70
|
|
|
71
71
|
def list_conflicts(conn: sqlite3.Connection, limit: int = 100) -> List[Dict[str, Any]]:
|
|
72
72
|
rows: List[Dict[str, Any]] = []
|
|
73
|
-
|
|
73
|
+
cols = {r[1] for r in conn.execute("PRAGMA table_info(fact_conflicts)")}
|
|
74
|
+
has_prov = "pack_id" in cols
|
|
75
|
+
extra = ", pack_id, source_refs_json, quote, about_hint" if has_prov else ""
|
|
76
|
+
for row in conn.execute(
|
|
74
77
|
"SELECT conflict_id, subject_entity_id, predicate, incumbent_object_id,"
|
|
75
|
-
" challenger_value, challenger_confidence, status, created_at"
|
|
78
|
+
" challenger_value, challenger_confidence, status, created_at" + extra +
|
|
76
79
|
" FROM fact_conflicts WHERE status='pending'"
|
|
77
80
|
" ORDER BY created_at DESC LIMIT ?", (min(int(limit), 500),)):
|
|
81
|
+
cid, subj, pred, incumbent, value, conf, status, created = row[:8]
|
|
82
|
+
pack_id, refs_json, quote, hint = (row[8:12] if has_prov else (None, None, None, None))
|
|
78
83
|
try:
|
|
79
84
|
val = json.loads(value)
|
|
80
85
|
except (json.JSONDecodeError, TypeError):
|
|
@@ -84,7 +89,9 @@ def list_conflicts(conn: sqlite3.Connection, limit: int = 100) -> List[Dict[str,
|
|
|
84
89
|
"kind": "quarantine" if is_q else "conflict",
|
|
85
90
|
"reason": str(incumbent)[len("quarantine:"):] if is_q else None,
|
|
86
91
|
"incumbent_object_id": incumbent, "value": val,
|
|
87
|
-
"confidence": conf, "created_at": created
|
|
92
|
+
"confidence": conf, "created_at": created,
|
|
93
|
+
"pack_id": pack_id, "quote": quote, "about_hint": hint,
|
|
94
|
+
"promotable": bool(pack_id)})
|
|
88
95
|
return rows
|
|
89
96
|
|
|
90
97
|
|
|
@@ -224,3 +231,182 @@ def run_pack_backfill(conn: sqlite3.Connection, pack_id: str, limit: int = 500)
|
|
|
224
231
|
conn.commit()
|
|
225
232
|
stats["quarantined"] = writer.stats.get("quarantined", 0) - stats.pop("quarantined0")
|
|
226
233
|
return stats
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def predicate_schemas(conn: sqlite3.Connection) -> Dict[str, Any]:
|
|
237
|
+
"""Per-predicate field schemas for the Fact Editor (W4.6): enum options,
|
|
238
|
+
person-typed flags, free-text fields — straight from the bundled contracts,
|
|
239
|
+
so the editor can never drift from what the writer accepts."""
|
|
240
|
+
from .packs import load_packs
|
|
241
|
+
from .registry import bundled_pack_dir
|
|
242
|
+
|
|
243
|
+
out: Dict[str, Any] = {}
|
|
244
|
+
for pid, pack in load_packs(bundled_pack_dir()).items():
|
|
245
|
+
for pred in pack.predicates.values():
|
|
246
|
+
fields: Dict[str, Any] = {}
|
|
247
|
+
if pred.value_schema:
|
|
248
|
+
for name, spec in pred.value_schema.items():
|
|
249
|
+
if isinstance(spec, dict) and spec.get("enum"):
|
|
250
|
+
fields[name] = {"kind": "enum", "options": list(spec["enum"])}
|
|
251
|
+
elif isinstance(spec, list):
|
|
252
|
+
fields[name] = {"kind": "enum", "options": list(spec)}
|
|
253
|
+
elif name in ("person", "member"):
|
|
254
|
+
fields[name] = {"kind": "person"}
|
|
255
|
+
else:
|
|
256
|
+
fields[name] = {"kind": "text"}
|
|
257
|
+
elif pred.values:
|
|
258
|
+
fields["__value__"] = {"kind": "enum", "options": list(pred.values)}
|
|
259
|
+
else:
|
|
260
|
+
fields["__value__"] = {"kind": "text"}
|
|
261
|
+
out[pred.name] = {"pack": pid, "fields": fields,
|
|
262
|
+
"key_fields": list(pred.key_fields or []),
|
|
263
|
+
"temporal": pred.temporal}
|
|
264
|
+
return out
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def promote_conflict(conn: sqlite3.Connection, conflict_id: str, *,
|
|
268
|
+
subject_entity_id: str = "", new_person_name: str = "",
|
|
269
|
+
value: Any = None, to_owner: bool = False) -> Dict[str, Any]:
|
|
270
|
+
"""W4.6 — the review queue's 'Edit & add': the owner supplies the identity
|
|
271
|
+
(or corrected fields) the machine refused to guess; the fact writes through
|
|
272
|
+
the FULL writer path and the correction lands in the ledger as GOLD."""
|
|
273
|
+
import json as _json
|
|
274
|
+
import uuid as _uuid
|
|
275
|
+
|
|
276
|
+
from .packs import load_packs
|
|
277
|
+
from .registry import bundled_pack_dir
|
|
278
|
+
from .writer import DerivationWriter
|
|
279
|
+
|
|
280
|
+
row = conn.execute(
|
|
281
|
+
"SELECT subject_entity_id, predicate, challenger_value, challenger_confidence,"
|
|
282
|
+
" pack_id, source_refs_json, quote, about_hint, status"
|
|
283
|
+
" FROM fact_conflicts WHERE conflict_id=?", (conflict_id,)).fetchone()
|
|
284
|
+
if not row:
|
|
285
|
+
raise ValueError(f"unknown conflict {conflict_id}")
|
|
286
|
+
subj0, predicate, val_json, conf, pack_id, refs_json, quote, hint, status = row
|
|
287
|
+
if status != "pending":
|
|
288
|
+
raise ValueError(f"conflict {conflict_id} already {status}")
|
|
289
|
+
if not pack_id:
|
|
290
|
+
raise ValueError("this row predates provenance capture — dismiss and let re-extraction recreate it")
|
|
291
|
+
pack = load_packs(bundled_pack_dir(), only=[pack_id]).get(pack_id)
|
|
292
|
+
if pack is None:
|
|
293
|
+
raise ValueError(f"unknown pack {pack_id}")
|
|
294
|
+
try:
|
|
295
|
+
stored_value = _json.loads(val_json or "null")
|
|
296
|
+
except (ValueError, TypeError):
|
|
297
|
+
stored_value = val_json
|
|
298
|
+
final_value = value if value is not None else stored_value
|
|
299
|
+
|
|
300
|
+
if to_owner:
|
|
301
|
+
subject = conn.execute("SELECT entity_id FROM entities WHERE is_self=1").fetchone()[0]
|
|
302
|
+
elif subject_entity_id:
|
|
303
|
+
ok = conn.execute("SELECT 1 FROM entities WHERE entity_id=?", (subject_entity_id,)).fetchone()
|
|
304
|
+
if not ok:
|
|
305
|
+
raise ValueError(f"unknown entity {subject_entity_id}")
|
|
306
|
+
subject = subject_entity_id
|
|
307
|
+
elif new_person_name.strip():
|
|
308
|
+
subject = f"ent_{_uuid.uuid4().hex[:16]}"
|
|
309
|
+
n = " ".join(new_person_name.strip().split())
|
|
310
|
+
cols = {r[1] for r in conn.execute("PRAGMA table_info(entities)")}
|
|
311
|
+
base = ["entity_id", "entity_type", "canonical_name", "normalized_name", "aliases_json", "is_self"]
|
|
312
|
+
vals = [subject, "person", n, n.lower(), "[]", 0]
|
|
313
|
+
for extra in ("created_at", "updated_at"):
|
|
314
|
+
if extra in cols:
|
|
315
|
+
base.append(extra); vals.append(None) # filled by SQL below
|
|
316
|
+
placeholders = ", ".join(
|
|
317
|
+
"datetime('now')" if b in ("created_at", "updated_at") else "?" for b in base)
|
|
318
|
+
conn.execute(
|
|
319
|
+
f"INSERT INTO entities ({', '.join(base)}) VALUES ({placeholders})",
|
|
320
|
+
[v for b, v in zip(base, vals) if b not in ("created_at", "updated_at")])
|
|
321
|
+
else:
|
|
322
|
+
raise ValueError("supply subject_entity_id, new_person_name, or to_owner")
|
|
323
|
+
|
|
324
|
+
writer = DerivationWriter(conn, model="owner-promote")
|
|
325
|
+
refs = _json.loads(refs_json or "[]")
|
|
326
|
+
out = writer.assert_pack_fact(
|
|
327
|
+
pack=pack, predicate=predicate, subject_entity_id=subject,
|
|
328
|
+
value=final_value, actor_role="authored", source_refs=refs,
|
|
329
|
+
confidence=1.0, quote=quote or "", about="owner")
|
|
330
|
+
from ...storage.db.write_gate import commit_connection, with_db_write
|
|
331
|
+
with with_db_write():
|
|
332
|
+
conn.execute("UPDATE fact_conflicts SET status='accepted', updated_at=datetime('now')"
|
|
333
|
+
" WHERE conflict_id=?", (conflict_id,))
|
|
334
|
+
try:
|
|
335
|
+
conn.execute(
|
|
336
|
+
"""INSERT INTO derivation_training_ledger
|
|
337
|
+
(ledger_id, stage, pack_id, pack_version, predicate, value_json,
|
|
338
|
+
about, quote, confidence, vstatus, written_object_id)
|
|
339
|
+
VALUES (?, 'owner_promote', ?, ?, ?, ?, ?, ?, 1.0, 'accepted', ?)""",
|
|
340
|
+
(f"dtl_{_uuid.uuid4().hex[:16]}", pack_id, pack.version, predicate,
|
|
341
|
+
_json.dumps(final_value, default=str), f"entity:{subject}",
|
|
342
|
+
quote or "", out.get("object_id")))
|
|
343
|
+
except sqlite3.OperationalError:
|
|
344
|
+
pass
|
|
345
|
+
commit_connection(conn)
|
|
346
|
+
return {"conflict_id": conflict_id, "outcome": out.get("outcome"),
|
|
347
|
+
"object_id": out.get("object_id"), "subject_entity_id": subject}
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def revise_fact(conn: sqlite3.Connection, object_id: str, *,
|
|
351
|
+
value: Any = None, subject_entity_id: str = "",
|
|
352
|
+
evidence_date: str = "", asserted_by: str = "") -> Dict[str, Any]:
|
|
353
|
+
"""W4.6 — owner revision of a live pack fact: closes the old row
|
|
354
|
+
(reason=owner_revision, belief clock inherited), re-inserts through keying
|
|
355
|
+
with confidence pinned 1.0. Field/date/subject edits only — a fact's KIND
|
|
356
|
+
never changes here (that is reject + a new fact)."""
|
|
357
|
+
import json as _json
|
|
358
|
+
import uuid as _uuid
|
|
359
|
+
|
|
360
|
+
from .packs import load_packs
|
|
361
|
+
from .registry import bundled_pack_dir
|
|
362
|
+
from .writer import DerivationWriter
|
|
363
|
+
|
|
364
|
+
row = conn.execute(
|
|
365
|
+
"SELECT object_key, payload_json, valid_from, ontology_id FROM signal_objects"
|
|
366
|
+
" WHERE object_id=? AND object_type='fact' AND valid_to IS NULL", (object_id,)).fetchone()
|
|
367
|
+
if not row:
|
|
368
|
+
raise ValueError(f"no live fact {object_id}")
|
|
369
|
+
key, pj, vf, pack_id = row
|
|
370
|
+
if not pack_id:
|
|
371
|
+
raise ValueError("legacy fact — use the verdict edit action")
|
|
372
|
+
p = _json.loads(pj or "{}")
|
|
373
|
+
predicate = str(p.get("predicate") or "")
|
|
374
|
+
pack = load_packs(bundled_pack_dir(), only=[pack_id]).get(pack_id)
|
|
375
|
+
if pack is None:
|
|
376
|
+
raise ValueError(f"unknown pack {pack_id}")
|
|
377
|
+
old_value = p.get("value_struct") if p.get("value_struct") is not None else p.get("object_value")
|
|
378
|
+
final_value = value if value is not None else old_value
|
|
379
|
+
subject = subject_entity_id or str(p.get("subject_entity_id") or "")
|
|
380
|
+
if subject_entity_id:
|
|
381
|
+
ok = conn.execute("SELECT 1 FROM entities WHERE entity_id=?", (subject_entity_id,)).fetchone()
|
|
382
|
+
if not ok:
|
|
383
|
+
raise ValueError(f"unknown entity {subject_entity_id}")
|
|
384
|
+
|
|
385
|
+
from ...storage.db.write_gate import commit_connection, with_db_write
|
|
386
|
+
with with_db_write():
|
|
387
|
+
conn.execute("UPDATE signal_objects SET valid_to=?, updated_at=datetime('now'),"
|
|
388
|
+
" updated_by='owner_revision' WHERE object_id=?",
|
|
389
|
+
((evidence_date or str(vf)), object_id))
|
|
390
|
+
commit_connection(conn)
|
|
391
|
+
writer = DerivationWriter(conn, model="owner-revise")
|
|
392
|
+
out = writer.assert_pack_fact(
|
|
393
|
+
pack=pack, predicate=predicate, subject_entity_id=subject,
|
|
394
|
+
value=final_value, actor_role="authored",
|
|
395
|
+
source_refs=p.get("source_refs") or [], confidence=1.0,
|
|
396
|
+
quote=str(p.get("quote") or ""), about="owner",
|
|
397
|
+
event_date=(evidence_date or str(vf)[:10]) or None)
|
|
398
|
+
with with_db_write():
|
|
399
|
+
try:
|
|
400
|
+
conn.execute(
|
|
401
|
+
"""INSERT INTO derivation_training_ledger
|
|
402
|
+
(ledger_id, stage, pack_id, predicate, value_json, about, confidence,
|
|
403
|
+
vstatus, vreason, written_object_id)
|
|
404
|
+
VALUES (?, 'owner_edit', ?, ?, ?, ?, 1.0, 'accepted', ?, ?)""",
|
|
405
|
+
(f"dtl_{_uuid.uuid4().hex[:16]}", pack_id, predicate,
|
|
406
|
+
_json.dumps(final_value, default=str), f"entity:{subject}",
|
|
407
|
+
f"revised_from:{object_id}", out.get("object_id")))
|
|
408
|
+
except sqlite3.OperationalError:
|
|
409
|
+
pass
|
|
410
|
+
commit_connection(conn)
|
|
411
|
+
return {"revised_from": object_id, "outcome": out.get("outcome"),
|
|
412
|
+
"object_id": out.get("object_id")}
|
|
@@ -100,7 +100,7 @@ LOSS_EVIDENCE = ("died", "passed", "passing", "funeral", "loss of", "death", "re
|
|
|
100
100
|
|
|
101
101
|
def relationship_role_check(role: str, person: str, record_text: str):
|
|
102
102
|
"""A1 role-evidence guard (measured 2026-08-26 full-run): the 27B verifier
|
|
103
|
-
CONSISTENTLY accepts possessive misattribution ("
|
|
103
|
+
CONSISTENTLY accepts possessive misattribution ("Nora and her boyfriend Theo"
|
|
104
104
|
-> owner's partner) — textual support without subject discipline. Rules,
|
|
105
105
|
all deterministic:
|
|
106
106
|
1. A kin-term PERSON ("Mom", "brother") is self-evidencing -> owner.
|
|
@@ -239,7 +239,7 @@ Hard rules:
|
|
|
239
239
|
- Extract only what this record actually states about the OWNER. No guesses, no world knowledge.
|
|
240
240
|
- Every assertion MUST carry "about": "owner" if the fact is about the record's author-owner,
|
|
241
241
|
"other:<name>" if the record states it about someone else (their appointment, their partner,
|
|
242
|
-
their loss — e.g. "
|
|
242
|
+
their loss — e.g. "Nora and her boyfriend Theo" -> about: "other:Nora"), or "unclear" if you
|
|
243
243
|
cannot tell. Facts about others are NOT discarded — they are routed to that person's dossier —
|
|
244
244
|
so NEVER launder a third party's fact into "owner" to save it.
|
|
245
245
|
The about field does NOT make extraction stricter: extract exactly what you would have
|
|
@@ -154,18 +154,33 @@ class DerivationWriter:
|
|
|
154
154
|
).fetchone()
|
|
155
155
|
return row[0] if row else None
|
|
156
156
|
|
|
157
|
-
def _quarantine(self, subject_entity_id: str, predicate: str, value, confidence: float,
|
|
157
|
+
def _quarantine(self, subject_entity_id: str, predicate: str, value, confidence: float,
|
|
158
|
+
reason: str, *, pack=None, source_refs=None, quote: str = "", about: str = ""):
|
|
158
159
|
"""A3 quarantine: nothing is silently lost — unroutable assertions land in
|
|
159
|
-
fact_conflicts (the
|
|
160
|
+
fact_conflicts (the review queue) WITH their provenance (migration 68), so
|
|
161
|
+
the owner can promote them into facts without minting evidence-less rows."""
|
|
160
162
|
import uuid as _uuid
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
163
|
+
hint = about[6:] if isinstance(about, str) and about.startswith("other:") else ""
|
|
164
|
+
try:
|
|
165
|
+
self.conn.execute(
|
|
166
|
+
"""INSERT INTO fact_conflicts (conflict_id, subject_entity_id, predicate,
|
|
167
|
+
incumbent_object_id, challenger_value, challenger_confidence,
|
|
168
|
+
pack_id, source_refs_json, quote, about_hint)
|
|
169
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
|
170
|
+
(f"cfl_{_uuid.uuid4().hex[:12]}", subject_entity_id, predicate,
|
|
171
|
+
f"quarantine:{reason}", json.dumps(value, ensure_ascii=False, default=str)[:500],
|
|
172
|
+
float(confidence), getattr(pack, "pack", None),
|
|
173
|
+
json.dumps(source_refs or [], default=str)[:800], (quote or "")[:200], hint),
|
|
174
|
+
)
|
|
175
|
+
except Exception: # noqa: BLE001 — pre-migration-68 schema
|
|
176
|
+
self.conn.execute(
|
|
177
|
+
"""INSERT INTO fact_conflicts (conflict_id, subject_entity_id, predicate,
|
|
178
|
+
incumbent_object_id, challenger_value, challenger_confidence)
|
|
179
|
+
VALUES (?, ?, ?, ?, ?, ?)""",
|
|
180
|
+
(f"cfl_{_uuid.uuid4().hex[:12]}", subject_entity_id, predicate,
|
|
181
|
+
f"quarantine:{reason}", json.dumps(value, ensure_ascii=False, default=str)[:500],
|
|
182
|
+
float(confidence)),
|
|
183
|
+
)
|
|
169
184
|
self.stats["quarantined"] = self.stats.get("quarantined", 0) + 1
|
|
170
185
|
|
|
171
186
|
def assert_pack_fact(
|
|
@@ -200,11 +215,13 @@ class DerivationWriter:
|
|
|
200
215
|
self.stats["routed_dossier"] = self.stats.get("routed_dossier", 0) + 1
|
|
201
216
|
else:
|
|
202
217
|
self._quarantine(subject_entity_id, predicate, value, confidence,
|
|
203
|
-
reason=f"dossier_unresolved:{about[6:][:40]}"
|
|
218
|
+
reason=f"dossier_unresolved:{about[6:][:40]}",
|
|
219
|
+
pack=pack, source_refs=source_refs, quote=quote, about=about)
|
|
204
220
|
return {"outcome": "quarantined", "reason": "about=other unresolvable"}
|
|
205
221
|
else: # unclear — two passes could not agree on a subject
|
|
206
222
|
self._quarantine(subject_entity_id, predicate, value, confidence,
|
|
207
|
-
reason="about_unclear"
|
|
223
|
+
reason="about_unclear",
|
|
224
|
+
pack=pack, source_refs=source_refs, quote=quote, about=about)
|
|
208
225
|
return {"outcome": "quarantined", "reason": "about unclear"}
|
|
209
226
|
synth_preds = {q for e in pack.synthesis for q in (e.get("predicate") if isinstance(e.get("predicate"), list) else [e.get("predicate")])}
|
|
210
227
|
if actor_role == "synthesis":
|
|
@@ -228,7 +245,8 @@ class DerivationWriter:
|
|
|
228
245
|
if pred.name == "asp.milestone" and isinstance(value, dict):
|
|
229
246
|
if not self._milestone_attaches(subject_entity_id, str(value.get("goal_ref") or "")):
|
|
230
247
|
self._quarantine(subject_entity_id, predicate, value, confidence,
|
|
231
|
-
reason="milestone_without_goal"
|
|
248
|
+
reason="milestone_without_goal",
|
|
249
|
+
pack=pack, source_refs=source_refs, quote=quote, about=about)
|
|
232
250
|
return {"outcome": "quarantined", "reason": "milestone attaches to no stored goal"}
|
|
233
251
|
# F1.6 guard — every leaf of the value
|
|
234
252
|
for leaf in _value_leaves(value):
|
|
@@ -794,7 +794,7 @@ def compute_communities(conn: sqlite3.Connection) -> Dict[str, int]:
|
|
|
794
794
|
# A community label is a NAME: name-length, from a name-natured type.
|
|
795
795
|
def _labelable(eid: str) -> bool:
|
|
796
796
|
nm = names.get(eid, "").strip()
|
|
797
|
-
if not nm or len(nm) > 40 or len(nm.split()) > 4:
|
|
797
|
+
if not nm or len(nm) > 40 or len(nm.split()) > 4 or "\n" in nm:
|
|
798
798
|
return False
|
|
799
799
|
if types.get(eid, "") in ("goal", "conversation"):
|
|
800
800
|
return False
|
|
@@ -820,7 +820,12 @@ def compute_communities(conn: sqlite3.Connection) -> Dict[str, int]:
|
|
|
820
820
|
# FALLBACK; identity-matched historical names win, and genuinely
|
|
821
821
|
# new cores get one LLM-derived name (validated, else fallback).
|
|
822
822
|
community_cores[rank[comm]] = [str(m) for m in ranked]
|
|
823
|
-
|
|
823
|
+
try:
|
|
824
|
+
_apply_stable_names(conn, community_cores, labels_by_rank, names, eigen)
|
|
825
|
+
except Exception: # noqa: BLE001 — naming is an ENHANCEMENT; a lock or
|
|
826
|
+
# model failure mid-pass must never cost the deterministic labels
|
|
827
|
+
# (first live run: a transient 'database is locked' wiped them)
|
|
828
|
+
logger.exception("stable naming pass failed; deterministic labels stand")
|
|
824
829
|
logger.info(
|
|
825
830
|
"graph structural analytics: %d nodes / %d edges, betweenness k=%s, %.2fs",
|
|
826
831
|
n,
|
|
@@ -130,6 +130,9 @@ def list_facts(
|
|
|
130
130
|
"subject_name": subject_name,
|
|
131
131
|
"predicate": payload.get("predicate"),
|
|
132
132
|
"object_value": payload.get("object_value"),
|
|
133
|
+
# the FULL structured value — object_value is a 160-char display
|
|
134
|
+
# string and renders as cut JSON when a report runs long (W4.6)
|
|
135
|
+
"value_struct": payload.get("value_struct"),
|
|
133
136
|
"period_start": payload.get("period_start"),
|
|
134
137
|
"period_end": payload.get("period_end"),
|
|
135
138
|
"confidence": payload.get("confidence", fact["confidence"]),
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"get_data_explorer_table_prefs",
|
|
44
44
|
"get_database_explorer_summary",
|
|
45
45
|
"get_derivation_packs",
|
|
46
|
+
"get_derivation_schema",
|
|
46
47
|
"get_device_info",
|
|
47
48
|
"get_enrichment_lab_bundle_detail",
|
|
48
49
|
"get_enrichment_lab_bundles",
|
|
@@ -133,6 +134,7 @@
|
|
|
133
134
|
"post_source_test_enrichment",
|
|
134
135
|
"post_source_test_enrichment_trigger",
|
|
135
136
|
"post_source_test_ingestion",
|
|
137
|
+
"promote_fact_conflict",
|
|
136
138
|
"put_community_name",
|
|
137
139
|
"put_conversation_context",
|
|
138
140
|
"put_conversation_context_llm_config",
|
|
@@ -156,6 +158,7 @@
|
|
|
156
158
|
"read_jsonl_file",
|
|
157
159
|
"replay_projection",
|
|
158
160
|
"replay_projection_preview",
|
|
161
|
+
"revise_pack_fact",
|
|
159
162
|
"routine_has_active_run",
|
|
160
163
|
"run_pack_backfill",
|
|
161
164
|
"set_device_name",
|
|
@@ -93,9 +93,27 @@ def fetch_direct_facts(
|
|
|
93
93
|
"altitude": altitude or "stated", "pack": pack,
|
|
94
94
|
"evidence_count": len(refs) if isinstance(refs, list) else 0,
|
|
95
95
|
})
|
|
96
|
+
# Durable facts (a standing role/status: "mom, parent, active") outrank event
|
|
97
|
+
# facts ("met X at the saloon") in a known-item answer. Recency-only ordering
|
|
98
|
+
# let a month of introductions push the owner's parents past the compose cap:
|
|
99
|
+
# live 2026-08-26, "Who's in my family?" listed 16 met-events and cut
|
|
100
|
+
# mom/brother while keeping them in store. Stable sort keeps recency DESC
|
|
101
|
+
# within each band, so event feeds ("what happened with X?") are unaffected
|
|
102
|
+
# below the durable block.
|
|
103
|
+
out.sort(key=lambda f: 0 if _is_durable(f.get("value")) else 1)
|
|
96
104
|
return out or None
|
|
97
105
|
|
|
98
106
|
|
|
107
|
+
def _is_durable(value: Any) -> bool:
|
|
108
|
+
"""A fact whose value carries a standing role/status rather than an event."""
|
|
109
|
+
if isinstance(value, str):
|
|
110
|
+
try:
|
|
111
|
+
value = json.loads(value)
|
|
112
|
+
except (json.JSONDecodeError, TypeError):
|
|
113
|
+
return False
|
|
114
|
+
return isinstance(value, dict) and bool(value.get("role") or value.get("status"))
|
|
115
|
+
|
|
116
|
+
|
|
99
117
|
def _fmt_value(v: Any) -> str:
|
|
100
118
|
if isinstance(v, str):
|
|
101
119
|
try:
|