memleaf 0.2.66__tar.gz → 0.2.67__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.
- {memleaf-0.2.66 → memleaf-0.2.67}/CHANGELOG.md +13 -0
- {memleaf-0.2.66/src/memleaf.egg-info → memleaf-0.2.67}/PKG-INFO +1 -1
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/acceptance-evidence-guide.md +11 -10
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/automatic-processing-route.md +26 -26
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/migration-preflight.md +6 -5
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/remember-incremental-route.md +19 -19
- {memleaf-0.2.66 → memleaf-0.2.67}/pyproject.toml +1 -1
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/__init__.py +1 -1
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/cli.py +2 -2
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/config.py +8 -6
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/hermes_provider/plugin.yaml +1 -1
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/installer.py +71 -6
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/mcp_server.py +2 -2
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/migration.py +12 -5
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/process_jobs.py +18 -12
- memleaf-0.2.67/src/memleaf/processing.py +22 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/processing_route.py +31 -12
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/service.py +17 -46
- {memleaf-0.2.66 → memleaf-0.2.67/src/memleaf.egg-info}/PKG-INFO +1 -1
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_a083_regressions.py +73 -73
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_a47_regressions.py +14 -8
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_artifact_verification.py +35 -6
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_control_absence_contract.py +12 -6
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_incremental_execution.py +7 -3
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_migration_backup.py +18 -1
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_processed_state_contract.py +15 -9
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_processing_entrypoints.py +23 -19
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_processing_route.py +25 -17
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_provider_compatibility.py +53 -2
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_remember_route.py +24 -19
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_source_followup_contract.py +60 -42
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/verify_distribution.py +70 -0
- memleaf-0.2.66/src/memleaf/processing.py +0 -535
- {memleaf-0.2.66 → memleaf-0.2.67}/LICENSE +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/MANIFEST.in +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/README.en.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/README.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/body-compaction.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/candidate-reconciliation.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/capture-budget-design.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/config-migrations.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/core-refactor.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/development-closeout.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/evidence-retention.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/explicit-memory-update.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/extraction-latency.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/gate-evidence-boundary.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/general-processing.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/hermes-mcp-runtime.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/hermes-provider-compatibility.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/host-acceptance-runbook.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/immutable-release-assets.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/incremental-commit-contract.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/incremental-execution.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/incremental-native-comparison.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/incremental-partial-recovery.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/incremental-planner-preview.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/incremental-runtime-contract.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/incremental-scope-registration.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/incremental-selected-retention.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/installed-artifact-verification.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/memory-state-contract.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/processing-quality-acceptance.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/public-query-integrity.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/query-performance.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/runtime-state-retention.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/semantic-extraction-protocol.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/source-work-contract.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/docs/v0.2.26-processing-status.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/examples/README.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/examples/basic_usage.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/examples/incremental_acceptance.json +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/examples/mcp_stdio.ndjson +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/examples/query_benchmark.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/install.ps1 +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/install.sh +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/setup.cfg +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/__main__.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/acceptance.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/adapters/__init__.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/adapters/antigravity.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/adapters/base.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/adapters/codex.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/adapters/hermes.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/admission.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/batch_review.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/budget.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/capture.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/compaction.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/create_coordinator.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/credentials.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/evidence_budget.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/evidence_policy.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/evidence_structure.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/evidence_syntax.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/explicit_text_source.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/extraction_budget.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/extraction_capability.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/extraction_work_state.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/frontmatter.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/hermes_provider/README.md +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/hermes_provider/__init__.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/hermes_provider/_mcp_client.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/hermes_provider/_provider.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/hermes_provider/_shared.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/hermes_provider/evidence_budget.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/hermes_provider/provider_compatibility.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/hermes_runtime.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/host_events.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/host_runtime.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/inbox.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/incremental_commit.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/incremental_dates.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/incremental_execution.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/incremental_journal.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/incremental_native.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/incremental_partial.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/incremental_preview.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/incremental_prompts.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/incremental_protocol.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/incremental_recovery.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/incremental_run_state.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/incremental_runtime.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/incremental_scopes.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/incremental_selection.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/index.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/inspection.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/legacy_update_journal.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/llm/__init__.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/llm/base.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/llm/claude_compatible.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/llm/gemini.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/llm/openai_compatible.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/llm/router.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/llm/thinking.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/locking.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/memory_commit.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/memory_planner.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/memory_retraction.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/memory_update.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/memory_writer.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/model_capabilities.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/model_discovery.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/model_execution.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/models.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/native_index.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/native_registration.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/parallel_model.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/planning_context.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/process_common.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/process_journal.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/process_owner.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/prompts.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/provenance.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/provider_compatibility.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/query_clock.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/query_progress.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/query_scan.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/receipt_codec.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/recording_policy.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/redaction.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/remember_route.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/retention.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/retrieval.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/retrieval_gate.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/runtime_retention.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/scope_maintenance.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/scope_state.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/semantic_maintenance.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/semantic_protocol.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/single_pass_memory_planner.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/single_pass_plan.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/source_policy.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/state_layout.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/subprocess_flags.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/summary_batch.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/target_reconciliation.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/turn_audit.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/turn_plan.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/update_coordinator.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/update_review.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/validation.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf/vault.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf.egg-info/SOURCES.txt +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf.egg-info/dependency_links.txt +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf.egg-info/entry_points.txt +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/src/memleaf.egg-info/top_level.txt +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/acceptance_oracles.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/candidate_update_fixtures.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/incremental_test_support.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/platform_smoke.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/release_assets.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/run_contracts.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_acceptance.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_acceptance_boundaries.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_body_compaction.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_candidate_reconciliation.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_contract_reporter.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_create_memory_contract.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_development_closeout.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_explicit_memory_update.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_explicit_update_contract.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_g1_memory_contract.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_g2_source_contract.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_hermes_native_provision.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_hermes_source_metadata.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_incremental_commit.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_incremental_configured_runtime.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_incremental_dates.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_incremental_execution_recovery.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_incremental_native.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_incremental_partial.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_incremental_partial_boundaries.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_incremental_partial_recovery.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_incremental_preview.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_incremental_protocol.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_incremental_recovery.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_incremental_remember.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_incremental_remember_recovery.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_incremental_scope_recovery.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_incremental_scopes.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_inspection_read_budget.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_mcp_retrieval_fallback.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_migration_runtime.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_native_read_stability.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_planner_provenance_contract.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_platform_contracts.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_processing_route_recovery.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_public_query_integrity.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_query_benchmark.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_query_clock.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_query_progress.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_query_scan_reuse.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_release_assets.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_remember_route_recovery.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_revision_target_integrity.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_runtime_retention.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_runtime_retention_observation.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_runtime_retention_recovery.py +0 -0
- {memleaf-0.2.66 → memleaf-0.2.67}/tests_public/test_vault_binding_contract.py +0 -0
|
@@ -4,6 +4,19 @@ All notable changes to memleaf are documented here.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.2.67 — 2026-09-20
|
|
8
|
+
|
|
9
|
+
### Incremental-only processing and release integrity
|
|
10
|
+
|
|
11
|
+
- Remove the executable legacy processing/remember engine. New Vaults use the
|
|
12
|
+
incremental runner for automatic processing, explicit remember, MCP/CLI and
|
|
13
|
+
detached jobs; retained legacy settings/jobs remain inspectable but fail closed.
|
|
14
|
+
- Fix the v0.2.66 Hermes Provider manifest drift by aligning Core and Provider at
|
|
15
|
+
0.2.67 and rejecting an internally inconsistent package before host/Vault changes.
|
|
16
|
+
- Gate source and wheel/sdist verification on one version identity across package
|
|
17
|
+
metadata, Core `__version__`, Hermes `plugin.yaml` and sdist project metadata.
|
|
18
|
+
|
|
19
|
+
|
|
7
20
|
## 0.2.66 — 2026-09-20
|
|
8
21
|
|
|
9
22
|
### Reconcile divergent local candidates
|
|
@@ -24,16 +24,17 @@ the suite count or from module-name references.
|
|
|
24
24
|
|
|
25
25
|
## Current route semantics
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
`
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
failed receipts or request counters to
|
|
27
|
+
The v0.2.67 candidate has one processing engine: incremental. New Vaults default
|
|
28
|
+
both `process.automatic_pipeline` and `process.remember_pipeline` to
|
|
29
|
+
`incremental`. A retained `legacy` value from an older Vault is not executable;
|
|
30
|
+
migration preflight reports it as `legacy_pipeline_configuration`, and runtime
|
|
31
|
+
entry points reject it with `legacy_pipeline_removed`.
|
|
32
|
+
|
|
33
|
+
A successfully installed candidate is still not proof that production migration is
|
|
34
|
+
safe. Existing legacy queue/control records retain their identity for diagnosis and
|
|
35
|
+
must be settled or explicitly reviewed; they are not reinterpreted as incremental
|
|
36
|
+
work. Do not erase old work, failed receipts or request counters to obtain a clean
|
|
37
|
+
preflight result.
|
|
37
38
|
|
|
38
39
|
## Preparation with no paid calls
|
|
39
40
|
|
|
@@ -1,31 +1,29 @@
|
|
|
1
|
-
# Automatic processing
|
|
1
|
+
# Automatic processing on the incremental engine
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
`process_incremental` and selected `remember_incremental` remain
|
|
7
|
-
|
|
3
|
+
As of the v0.2.67 candidate, `Memleaf.process()`, CLI `process`, MCP `process`
|
|
4
|
+
and the detached job worker all execute through the existing incremental runner.
|
|
5
|
+
There is no executable legacy processing engine and no runtime fallback to it.
|
|
6
|
+
`process_incremental` and selected `remember_incremental` remain facades on the
|
|
7
|
+
same runner, request budget and commit journal.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
selection; see `remember-incremental-route.md`. Switching automatic processing
|
|
14
|
-
alone does not enable the text route. Both use the same incremental runner.
|
|
9
|
+
New Vaults default to incremental processing. Existing Vaults that still contain a
|
|
10
|
+
`legacy` pipeline setting remain readable for migration inspection, but processing
|
|
11
|
+
fails closed with `legacy_pipeline_removed` until the operator explicitly updates
|
|
12
|
+
the configuration after the required stop/backup/preflight procedure.
|
|
15
13
|
|
|
16
|
-
##
|
|
14
|
+
## One engine, compatibility selector only
|
|
17
15
|
|
|
18
|
-
The
|
|
16
|
+
The configuration field is retained for migration visibility:
|
|
19
17
|
|
|
20
18
|
```yaml
|
|
21
19
|
process:
|
|
22
|
-
automatic_pipeline:
|
|
20
|
+
automatic_pipeline: incremental
|
|
23
21
|
```
|
|
24
22
|
|
|
25
|
-
A missing field
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
A missing field resolves to incremental. `incremental` is the only executable
|
|
24
|
+
value. A retained `legacy` value is a migration blocker; unknown names, nonstrings
|
|
25
|
+
and malformed configuration fail explicitly. Nothing silently reinterprets an old
|
|
26
|
+
legacy queue or configuration as new incremental work.
|
|
29
27
|
|
|
30
28
|
The optional per-call override affects that call only:
|
|
31
29
|
|
|
@@ -134,9 +132,11 @@ concurrent planners and stale responses.
|
|
|
134
132
|
|
|
135
133
|
## Queue binding and cutover
|
|
136
134
|
|
|
137
|
-
An accepted job binds
|
|
138
|
-
|
|
139
|
-
|
|
135
|
+
An accepted job binds the incremental engine, normalized scope and recover flag.
|
|
136
|
+
A same-session request with different controls cannot silently coalesce into it.
|
|
137
|
+
Historical queue records that are missing the incremental route, or explicitly
|
|
138
|
+
name `legacy`, are retained for diagnosis but blocked with
|
|
139
|
+
`legacy_pipeline_removed`; they are never executed by a compatibility engine.
|
|
140
140
|
Malformed stored controls fail validation without resetting the queue.
|
|
141
141
|
|
|
142
142
|
A waiting job refuses execution when the configured default has changed since its
|
|
@@ -185,8 +185,8 @@ model configuration absent. Queue errors do not become successful NO_MEMORY.
|
|
|
185
185
|
|
|
186
186
|
## Validation and outstanding work
|
|
187
187
|
|
|
188
|
-
Public tests cover
|
|
189
|
-
batch caps, redacted ID selection, CLI/MCP/queue controls,
|
|
188
|
+
Public tests cover incremental defaults, explicit rejection of legacy execution,
|
|
189
|
+
exact scope, source ordering, batch caps, redacted ID selection, CLI/MCP/queue controls,
|
|
190
190
|
old queue compatibility, safe summaries, native NO_CHANGE, index/cleanup failures,
|
|
191
191
|
source/target edits, Forget, concurrent dispatch, and a real child process exiting
|
|
192
192
|
after its saved response. All Vaults and model responses in tests are synthetic.
|
|
@@ -207,8 +207,8 @@ Native installed-artifact results must come from the exact candidate's CI
|
|
|
207
207
|
reports, not from a phase document or a prior green build. A native package test
|
|
208
208
|
with a host-interface stub is not actual host acceptance.
|
|
209
209
|
|
|
210
|
-
|
|
211
|
-
|
|
210
|
+
Automatic processing and text remember both use the incremental engine by default.
|
|
211
|
+
`--dry-run` may still call the configured model;
|
|
212
212
|
acceptance plan-only mode is the no-model preparation path. See
|
|
213
213
|
[the acceptance evidence guide](acceptance-evidence-guide.md) for the remaining
|
|
214
214
|
gates. The fixed 1,861-codepoint/3,587-byte main prompt is unchanged.
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# Migration preflight and private local backup (G4e)
|
|
2
2
|
|
|
3
|
-
This
|
|
4
|
-
contract (FS178-179, FS188, FS192 and FS196). It
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
This command implements the preparation portion of the controlled migration
|
|
4
|
+
contract (FS178-179, FS188, FS192 and FS196). It does not stop processes, rewrite
|
|
5
|
+
business records, reset budgets, restore a Vault, or rewrite pipeline settings.
|
|
6
|
+
The v0.2.67 candidate itself has only the incremental engine; a retained
|
|
7
|
+
`legacy` setting is reported as `legacy_pipeline_configuration` and must be
|
|
8
|
+
handled explicitly after writers are stopped and a verified backup exists.
|
|
8
9
|
|
|
9
10
|
## Inspect before changing anything
|
|
10
11
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Text remember on the incremental engine
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
incremental execution. This
|
|
5
|
-
budget, native comparator, compiler and shared
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
As of the v0.2.67 candidate, `Memleaf.remember()` and the MCP `remember` tool use
|
|
4
|
+
incremental execution as their only engine. This remains an adapter to the same
|
|
5
|
+
selected-retention runner, budget, native comparator, compiler and shared
|
|
6
|
+
MemoryWriter; it does not create a second planner. There is no executable legacy
|
|
7
|
+
remember path and no fallback to it.
|
|
8
8
|
|
|
9
9
|
## Selection and compatibility
|
|
10
10
|
|
|
@@ -26,13 +26,13 @@ if result["retry_available"]:
|
|
|
26
26
|
)
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
The
|
|
30
|
-
`
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
The retained `process.remember_pipeline` field defaults to `incremental`.
|
|
30
|
+
`incremental` is the only executable value; an old `legacy` value is preserved
|
|
31
|
+
for migration inspection but is rejected with `legacy_pipeline_removed`. The
|
|
32
|
+
per-call `pipeline` argument is now only a compatibility selector for
|
|
33
|
+
`incremental`. Unknown values fail explicitly. The MCP tool exposes only
|
|
34
|
+
`incremental` plus the existing `recover` and `source_time` controls. A
|
|
35
|
+
supplied model/router still must meet the existing single-dispatch contract.
|
|
36
36
|
|
|
37
37
|
`content` and its `text` alias contain the actual submitted user material. Supplying
|
|
38
38
|
both with different values is rejected on the incremental route. One text request
|
|
@@ -145,12 +145,12 @@ consent or report a damaged state as NO_MEMORY.
|
|
|
145
145
|
|
|
146
146
|
## Cutover and validation
|
|
147
147
|
|
|
148
|
-
|
|
149
|
-
live acceptance. Older
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
148
|
+
Production migration still requires controlled stop/backup/upgrade/restart and
|
|
149
|
+
live acceptance. Older binaries must be stopped before changing a retained legacy
|
|
150
|
+
configuration; changing a config key does not kill an old process or make
|
|
151
|
+
mixed-version writes safe. This candidate changes the package default to
|
|
152
|
+
incremental but does not itself mutate a production Vault, run a real model, or
|
|
153
|
+
prove native Hermes lifecycle acceptance.
|
|
154
154
|
|
|
155
155
|
Deterministic tests cover one-user projection, origin provenance, same/new intents,
|
|
156
156
|
legacy-route collisions, explicit and configured selection, unchanged originating
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Local-first Markdown memory core for AI agents."""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.2.
|
|
3
|
+
__version__ = "0.2.67"
|
|
4
4
|
|
|
5
5
|
from .config import DEFAULT_CONFIG, default_config, load_config, save_config
|
|
6
6
|
from .frontmatter import FrontmatterError, dump_frontmatter, dump_yaml, load_yaml, parse_frontmatter
|
|
@@ -94,8 +94,8 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
94
94
|
process.add_argument("--source", default=None)
|
|
95
95
|
process.add_argument("--session-id", default=None)
|
|
96
96
|
process.add_argument("--scope", default=None)
|
|
97
|
-
process.add_argument("--pipeline", choices=("
|
|
98
|
-
help="
|
|
97
|
+
process.add_argument("--pipeline", choices=("incremental",), default=None,
|
|
98
|
+
help="compatibility override; incremental is the only processing engine")
|
|
99
99
|
process.add_argument("--recover", action="store_true",
|
|
100
100
|
help="allow remaining incremental transport recovery, not partial replan")
|
|
101
101
|
process.add_argument("--dry-run", action="store_true", help="no source Vault writes; may call the configured model")
|
|
@@ -89,8 +89,8 @@ DEFAULT_CONFIG: dict[str, Any] = {
|
|
|
89
89
|
"memory_compact_threshold_tokens": 100000,
|
|
90
90
|
"memory_compact_candidate_ratio": 0.30,
|
|
91
91
|
"inbox_cleanup_hours": 24,
|
|
92
|
-
"automatic_pipeline": "
|
|
93
|
-
"remember_pipeline": "
|
|
92
|
+
"automatic_pipeline": "incremental",
|
|
93
|
+
"remember_pipeline": "incremental",
|
|
94
94
|
# Compatibility key: closed todo heads remain current identities.
|
|
95
95
|
"closed_todo_retention_days": 30,
|
|
96
96
|
"model_concurrency": DEFAULT_MODEL_CONCURRENCY,
|
|
@@ -225,10 +225,12 @@ def load_config(path: Path | str, *, vault: Path | str | None = None) -> dict[st
|
|
|
225
225
|
cleanup_hours = process.get("inbox_cleanup_hours") if isinstance(process, Mapping) else None
|
|
226
226
|
if type(cleanup_hours) is not int or cleanup_hours < 0:
|
|
227
227
|
raise ValueError("invalid memleaf process.inbox_cleanup_hours")
|
|
228
|
-
|
|
228
|
+
# Legacy values remain parseable only so old Vaults can be inspected and migrated.
|
|
229
|
+
# Runtime selection rejects them; new/default configurations are incremental-only.
|
|
230
|
+
automatic_pipeline = process.get("automatic_pipeline", "incremental")
|
|
229
231
|
if not isinstance(automatic_pipeline, str) or automatic_pipeline not in {"legacy", "incremental"}:
|
|
230
232
|
raise ValueError("invalid memleaf process.automatic_pipeline")
|
|
231
|
-
remember_pipeline = process.get("remember_pipeline", "
|
|
233
|
+
remember_pipeline = process.get("remember_pipeline", "incremental")
|
|
232
234
|
if not isinstance(remember_pipeline, str) or remember_pipeline not in {"legacy", "incremental"}:
|
|
233
235
|
raise ValueError("invalid memleaf process.remember_pipeline")
|
|
234
236
|
closed_todo_days = process.get("closed_todo_retention_days") if isinstance(process, Mapping) else None
|
|
@@ -296,11 +298,11 @@ def save_config(path: Path | str, config: Mapping[str, Any]) -> None:
|
|
|
296
298
|
if not isinstance(process, Mapping):
|
|
297
299
|
raise ValueError("invalid memleaf process settings")
|
|
298
300
|
normalized_process = dict(process)
|
|
299
|
-
pipeline = normalized_process.get("automatic_pipeline", "
|
|
301
|
+
pipeline = normalized_process.get("automatic_pipeline", "incremental")
|
|
300
302
|
if not isinstance(pipeline, str) or pipeline not in {"legacy", "incremental"}:
|
|
301
303
|
raise ValueError("invalid memleaf process.automatic_pipeline")
|
|
302
304
|
normalized_process["automatic_pipeline"] = pipeline
|
|
303
|
-
remember_pipeline = normalized_process.get("remember_pipeline", "
|
|
305
|
+
remember_pipeline = normalized_process.get("remember_pipeline", "incremental")
|
|
304
306
|
if not isinstance(remember_pipeline, str) or remember_pipeline not in {"legacy", "incremental"}:
|
|
305
307
|
raise ValueError("invalid memleaf process.remember_pipeline")
|
|
306
308
|
normalized_process["remember_pipeline"] = remember_pipeline
|
|
@@ -902,6 +902,44 @@ _MODEL_ROUTE_INCOMPATIBLE_ACTION = (
|
|
|
902
902
|
)
|
|
903
903
|
|
|
904
904
|
|
|
905
|
+
_PIPELINE_MIGRATION_REQUIRED_ACTION = (
|
|
906
|
+
"This Vault still selects the removed legacy processing engine. Stop all supported "
|
|
907
|
+
"writers, run migration-check, create and verify a migration backup, then set both "
|
|
908
|
+
"process.automatic_pipeline and process.remember_pipeline to incremental before "
|
|
909
|
+
"relying on automatic extraction or remember."
|
|
910
|
+
)
|
|
911
|
+
|
|
912
|
+
_PIPELINE_CONFIGURATION_INVALID_ACTION = (
|
|
913
|
+
"Repair the Vault process configuration before relying on memory processing. "
|
|
914
|
+
"v0.2.67 supports only the incremental execution engine."
|
|
915
|
+
)
|
|
916
|
+
|
|
917
|
+
|
|
918
|
+
def _pipeline_route_outcome(vault: Any) -> tuple[bool, str, str | None]:
|
|
919
|
+
"""Report whether this Vault can execute the sole incremental engine."""
|
|
920
|
+
try:
|
|
921
|
+
config = vault.config()
|
|
922
|
+
except Exception:
|
|
923
|
+
return False, "pipeline_configuration_invalid", _PIPELINE_CONFIGURATION_INVALID_ACTION
|
|
924
|
+
process = config.get("process") if isinstance(config, Mapping) else None
|
|
925
|
+
if not isinstance(process, Mapping):
|
|
926
|
+
return False, "pipeline_configuration_invalid", _PIPELINE_CONFIGURATION_INVALID_ACTION
|
|
927
|
+
values = (
|
|
928
|
+
process.get("automatic_pipeline", "incremental"),
|
|
929
|
+
process.get("remember_pipeline", "incremental"),
|
|
930
|
+
)
|
|
931
|
+
if any(value == "legacy" for value in values):
|
|
932
|
+
return False, "pipeline_migration_required", _PIPELINE_MIGRATION_REQUIRED_ACTION
|
|
933
|
+
if any(value != "incremental" for value in values):
|
|
934
|
+
return False, "pipeline_configuration_invalid", _PIPELINE_CONFIGURATION_INVALID_ACTION
|
|
935
|
+
return True, "ready", None
|
|
936
|
+
|
|
937
|
+
|
|
938
|
+
def _join_user_actions(*actions: str | None) -> str | None:
|
|
939
|
+
values = [action.strip() for action in actions if isinstance(action, str) and action.strip()]
|
|
940
|
+
return " ".join(values) if values else None
|
|
941
|
+
|
|
942
|
+
|
|
905
943
|
def _route_can_extract(vault: Any) -> bool:
|
|
906
944
|
"""Ask the production router whether this Vault's route can speak B3.
|
|
907
945
|
|
|
@@ -965,6 +1003,22 @@ def install_hermes(
|
|
|
965
1003
|
if mcp_runtime not in _MCP_RUNTIME_POLICIES:
|
|
966
1004
|
raise ValueError(f"unsupported Hermes MCP runtime policy: {mcp_runtime}")
|
|
967
1005
|
|
|
1006
|
+
# Reject an internally inconsistent package before reading or changing any
|
|
1007
|
+
# Hermes/Vault state. The post-copy check below remains as defense in depth.
|
|
1008
|
+
packaged_provider = Path(__file__).with_name("hermes_provider")
|
|
1009
|
+
packaged_provider_version = _provider_manifest_version(packaged_provider)
|
|
1010
|
+
if packaged_provider_version != core_version:
|
|
1011
|
+
return _failure_result(
|
|
1012
|
+
stage="provider_version",
|
|
1013
|
+
reason=(
|
|
1014
|
+
"packaged Hermes provider version mismatch: "
|
|
1015
|
+
f"core={core_version}, provider={packaged_provider_version or 'unknown'}"
|
|
1016
|
+
),
|
|
1017
|
+
core_version=core_version,
|
|
1018
|
+
provider_version=packaged_provider_version,
|
|
1019
|
+
vault=None,
|
|
1020
|
+
)
|
|
1021
|
+
|
|
968
1022
|
home = _home_from_environment()
|
|
969
1023
|
hermes_home = _hermes_home(home)
|
|
970
1024
|
try:
|
|
@@ -1082,11 +1136,16 @@ def install_hermes(
|
|
|
1082
1136
|
# here used to leave core and provider versions out of step. A *present*
|
|
1083
1137
|
# route that cannot speak B3 is reported separately, because advertising
|
|
1084
1138
|
# ``ready`` for it would promise extraction that can never run.
|
|
1085
|
-
model_ready,
|
|
1139
|
+
model_ready, model_processing_status, model_action = _model_route_outcome(
|
|
1086
1140
|
model, can_extract=_route_can_extract(vault)
|
|
1087
1141
|
)
|
|
1088
|
-
|
|
1089
|
-
|
|
1142
|
+
pipeline_ready, pipeline_processing_status, pipeline_action = _pipeline_route_outcome(vault)
|
|
1143
|
+
processing_status = (
|
|
1144
|
+
model_processing_status if pipeline_ready else pipeline_processing_status
|
|
1145
|
+
)
|
|
1146
|
+
install_action = _join_user_actions(pipeline_action, model_action)
|
|
1147
|
+
# Host integration is configured even when processing still needs an explicit
|
|
1148
|
+
# model route or a controlled legacy->incremental Vault migration.
|
|
1090
1149
|
|
|
1091
1150
|
provider_target = hermes_home / "plugins" / "memleaf"
|
|
1092
1151
|
provider_config = hermes_home / "memleaf.json"
|
|
@@ -1298,8 +1357,8 @@ def install_hermes(
|
|
|
1298
1357
|
"native_sources": native_registration,
|
|
1299
1358
|
"capture": capture_policy_status(vault.config()),
|
|
1300
1359
|
"processing_status": processing_status,
|
|
1301
|
-
"user_action_required": bool(
|
|
1302
|
-
"user_action":
|
|
1360
|
+
"user_action_required": bool(install_action),
|
|
1361
|
+
"user_action": install_action,
|
|
1303
1362
|
}
|
|
1304
1363
|
|
|
1305
1364
|
|
|
@@ -1357,9 +1416,12 @@ def install_codex(*, vault_path: Path | None = None) -> dict[str, Any]:
|
|
|
1357
1416
|
"codex": configured.to_dict(),
|
|
1358
1417
|
}
|
|
1359
1418
|
model_ready = model.get("status") in {"configured", "already_configured"}
|
|
1419
|
+
pipeline_ready, pipeline_processing_status, pipeline_action = _pipeline_route_outcome(vault)
|
|
1360
1420
|
actions: list[str] = []
|
|
1361
1421
|
if configured.user_action_required and configured.user_action:
|
|
1362
1422
|
actions.append(configured.user_action)
|
|
1423
|
+
if pipeline_action:
|
|
1424
|
+
actions.append(pipeline_action)
|
|
1363
1425
|
if not model_ready:
|
|
1364
1426
|
actions.append(
|
|
1365
1427
|
"Configure an independent memleaf Model Route for this Vault before relying on "
|
|
@@ -1372,7 +1434,10 @@ def install_codex(*, vault_path: Path | None = None) -> dict[str, Any]:
|
|
|
1372
1434
|
"vault": str(vault.root),
|
|
1373
1435
|
"vault_source": vault_source,
|
|
1374
1436
|
"model": model,
|
|
1375
|
-
"processing_status":
|
|
1437
|
+
"processing_status": (
|
|
1438
|
+
("ready" if model_ready else "model_route_required")
|
|
1439
|
+
if pipeline_ready else pipeline_processing_status
|
|
1440
|
+
),
|
|
1376
1441
|
"codex": configured.to_dict(),
|
|
1377
1442
|
"user_action_required": bool(actions),
|
|
1378
1443
|
"user_action": " ".join(actions) if actions else None,
|
|
@@ -303,7 +303,7 @@ _TOOLS: tuple[dict[str, Any], ...] = (
|
|
|
303
303
|
"session_id": {"type": "string"},
|
|
304
304
|
"scope": _text_or_texts_schema(),
|
|
305
305
|
"background": {"type": "boolean"},
|
|
306
|
-
"pipeline": {"type": "string", "enum": ["
|
|
306
|
+
"pipeline": {"type": "string", "enum": ["incremental"]},
|
|
307
307
|
"recover": {"type": "boolean"},
|
|
308
308
|
}
|
|
309
309
|
),
|
|
@@ -332,7 +332,7 @@ _TOOLS: tuple[dict[str, Any], ...] = (
|
|
|
332
332
|
"event_id": {"type": "string"},
|
|
333
333
|
"intent_id": {"type": "string"},
|
|
334
334
|
"scopes": _text_or_texts_schema(),
|
|
335
|
-
"pipeline": {"type": "string", "enum": ["
|
|
335
|
+
"pipeline": {"type": "string", "enum": ["incremental"]},
|
|
336
336
|
"recover": {"type": "boolean"},
|
|
337
337
|
"source_time": {"type": "string"},
|
|
338
338
|
},
|
|
@@ -12,7 +12,7 @@ import os
|
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
import platform
|
|
14
14
|
import re
|
|
15
|
-
from typing import Any
|
|
15
|
+
from typing import Any, Mapping
|
|
16
16
|
|
|
17
17
|
from . import __version__
|
|
18
18
|
from .inspection import _checked_snapshot, _snapshot, _fingerprint, existing_root
|
|
@@ -94,6 +94,7 @@ def _checks(service: Any, snapshot: dict[str, bytes]) -> dict:
|
|
|
94
94
|
warnings: set[str] = set()
|
|
95
95
|
counts: dict[str, int] = {}
|
|
96
96
|
config = None
|
|
97
|
+
configured: dict[str, Any] = {}
|
|
97
98
|
binding = {"status": "unknown"}
|
|
98
99
|
try:
|
|
99
100
|
binding = service.vault.identity_status()
|
|
@@ -106,6 +107,14 @@ def _checks(service: Any, snapshot: dict[str, bytes]) -> dict:
|
|
|
106
107
|
except (OSError, ValueError, UnicodeError, TypeError):
|
|
107
108
|
blockers.add("invalid_configuration")
|
|
108
109
|
if config is not None:
|
|
110
|
+
process_config = config.get("process", {}) if isinstance(config, Mapping) else {}
|
|
111
|
+
configured = {
|
|
112
|
+
key: process_config.get(key, "incremental") if isinstance(process_config, Mapping) else None
|
|
113
|
+
for key in ("automatic_pipeline", "remember_pipeline")
|
|
114
|
+
}
|
|
115
|
+
counts["legacy_pipeline_settings"] = sum(value == "legacy" for value in configured.values())
|
|
116
|
+
if counts["legacy_pipeline_settings"]:
|
|
117
|
+
blockers.add("legacy_pipeline_configuration")
|
|
109
118
|
native_unavailable, native_blockers = _native_source_readiness(service, config)
|
|
110
119
|
counts["unavailable_native_sources"] = native_unavailable
|
|
111
120
|
blockers.update(native_blockers)
|
|
@@ -187,10 +196,8 @@ def _checks(service: Any, snapshot: dict[str, bytes]) -> dict:
|
|
|
187
196
|
elif progress["status"] != "current":
|
|
188
197
|
blockers.add("unsettled_sources_require_review")
|
|
189
198
|
warnings.update(_EXTERNAL_CHECKS)
|
|
190
|
-
#
|
|
191
|
-
#
|
|
192
|
-
configured = {k: config["process"].get(k, "legacy") for k in
|
|
193
|
-
("automatic_pipeline", "remember_pipeline")} if config else {}
|
|
199
|
+
# Historical route settings are reported as migration facts. They are not
|
|
200
|
+
# executable by this release and are never silently rewritten here.
|
|
194
201
|
return {"local_status": "blocked" if blockers else "clear",
|
|
195
202
|
"blockers": sorted(blockers),
|
|
196
203
|
"backup_blockers": sorted(blockers & {"processing_owner_live", "queue_not_quiescent"}),
|
|
@@ -141,8 +141,9 @@ def _valid_state(value: Any) -> dict[str, Any]:
|
|
|
141
141
|
if not _valid_job_id(job_id) or not isinstance(raw, Mapping):
|
|
142
142
|
raise ProcessJobStateError("invalid process job record")
|
|
143
143
|
from .processing_route import PIPELINES
|
|
144
|
+
persisted_pipelines = PIPELINES | {"legacy"}
|
|
144
145
|
for field in ("pipeline", "configured_pipeline"):
|
|
145
|
-
if field in raw and (not isinstance(raw[field], str) or raw[field] not in
|
|
146
|
+
if field in raw and (not isinstance(raw[field], str) or raw[field] not in persisted_pipelines):
|
|
146
147
|
raise ProcessJobStateError("invalid process job pipeline")
|
|
147
148
|
if "recover" in raw and type(raw["recover"]) is not bool:
|
|
148
149
|
raise ProcessJobStateError("invalid process job recovery")
|
|
@@ -523,8 +524,8 @@ def _aggregate_attempt_results(attempts: list[Any]) -> dict[str, Any]:
|
|
|
523
524
|
if type(value) is int and value >= 0:
|
|
524
525
|
aggregate["pending_inbox_turns"] = value
|
|
525
526
|
break
|
|
526
|
-
#
|
|
527
|
-
#
|
|
527
|
+
# Historical legacy jobs can still produce a blocked migration result. Keep
|
|
528
|
+
# that safe reason in the top-level result, not only in attempt history.
|
|
528
529
|
for attempt in reversed(attempts):
|
|
529
530
|
value = attempt.get("result", {}) if isinstance(attempt, Mapping) else {}
|
|
530
531
|
if not isinstance(value, Mapping):
|
|
@@ -691,8 +692,7 @@ def enqueue(vault_path: Path | str, *, source: str, session_id: str, scope: Any
|
|
|
691
692
|
with vault.lock():
|
|
692
693
|
config = vault.config()
|
|
693
694
|
chosen = select_pipeline(config, pipeline)
|
|
694
|
-
|
|
695
|
-
if type(recover) is not bool or (chosen == "legacy" and recover):
|
|
695
|
+
if type(recover) is not bool:
|
|
696
696
|
raise ValueError("invalid_process_recovery")
|
|
697
697
|
state = _read_state(vault)
|
|
698
698
|
recovered = _recover_dead_active(state)
|
|
@@ -707,8 +707,7 @@ def enqueue(vault_path: Path | str, *, source: str, session_id: str, scope: Any
|
|
|
707
707
|
if job.get("status") in _ACTIVE | {"pending"}:
|
|
708
708
|
old_scope = normalize_scopes(job.get("scope")) if job.get("scope") is not None else None
|
|
709
709
|
if (job.get("pipeline", "legacy") != chosen or old_scope != scope
|
|
710
|
-
or job.get("recover", False) != recover
|
|
711
|
-
or job.get("configured_pipeline", "legacy") != configured):
|
|
710
|
+
or job.get("recover", False) != recover):
|
|
712
711
|
return {"accepted": False, "completed": False, "status": "blocked", "job_id": job_id,
|
|
713
712
|
"reason": "process_arguments_changed"}
|
|
714
713
|
if job.get("status") in _ACTIVE:
|
|
@@ -728,7 +727,7 @@ def enqueue(vault_path: Path | str, *, source: str, session_id: str, scope: Any
|
|
|
728
727
|
job_id = f"job-{uuid.uuid4().hex}"
|
|
729
728
|
job = {
|
|
730
729
|
"job_id": job_id, "source": source, "session_id": session_id,
|
|
731
|
-
"scope": scope, "pipeline": chosen, "configured_pipeline":
|
|
730
|
+
"scope": scope, "pipeline": chosen, "configured_pipeline": "incremental", "recover": recover,
|
|
732
731
|
"status": "pending", "accepted_at": _now(),
|
|
733
732
|
"updated_at": _now(), "owner_pid": None, "rerun_requested": False,
|
|
734
733
|
}
|
|
@@ -815,13 +814,20 @@ def run_worker(vault_path: Path | str, job_id: str) -> int:
|
|
|
815
814
|
try:
|
|
816
815
|
service = Memleaf(vault)
|
|
817
816
|
from .processing_route import select_pipeline
|
|
818
|
-
|
|
819
|
-
|
|
817
|
+
stored_pipeline = job.get("pipeline")
|
|
818
|
+
try:
|
|
819
|
+
select_pipeline(vault.config())
|
|
820
|
+
configured_code = None
|
|
821
|
+
except ValueError as error:
|
|
822
|
+
configured_code = str(error)
|
|
823
|
+
if stored_pipeline != "incremental" or configured_code is not None:
|
|
824
|
+
result = {"pipeline": "incremental", "execution_status": "blocked",
|
|
820
825
|
"coverage_status": "partial", "deferred_inbox_turns": 1,
|
|
821
|
-
"results": [{"execution_status": "blocked",
|
|
826
|
+
"results": [{"execution_status": "blocked",
|
|
827
|
+
"code": configured_code or "legacy_pipeline_removed"}]}
|
|
822
828
|
else:
|
|
823
829
|
result = service.process(source=job["source"], session_id=job["session_id"], scope=job.get("scope"),
|
|
824
|
-
pipeline=
|
|
830
|
+
pipeline="incremental", recover=job.get("recover", False))
|
|
825
831
|
terminal = _result_status(result if isinstance(result, Mapping) else {})
|
|
826
832
|
rerun = _finish(vault, job_id, status_value=terminal, result=result)
|
|
827
833
|
except Exception as error:
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Compatibility tombstone for the removed legacy processing engine.
|
|
2
|
+
|
|
3
|
+
memleaf v0.2.67 and later execute memory extraction only through the
|
|
4
|
+
incremental runtime. This module remains importable so older integrations fail
|
|
5
|
+
with an explicit migration error instead of a ModuleNotFoundError, but it no
|
|
6
|
+
longer contains or executes the legacy engine.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
from .process_common import ProcessingError
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Processor:
|
|
16
|
+
"""Removed legacy processor compatibility surface."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, service: Any):
|
|
19
|
+
raise ProcessingError("legacy_pipeline_removed")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
__all__ = ["Processor", "ProcessingError"]
|