mempalace-code 1.13.8__tar.gz → 1.14.2__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.
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/CHANGELOG.md +74 -1
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/PKG-INFO +3 -2
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/README.md +2 -1
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/code_retrieval_bench.py +193 -61
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/data/code_retrieval_queries.json +93 -37
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/OFFLINE_USAGE.md +6 -10
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/RELEASING.md +10 -6
- mempalace_code-1.14.2/docs/UPSTREAM_COMPARISON.md +256 -0
- mempalace_code-1.14.2/docs/operations/wing-migration.md +303 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/quality/scorecard.json +17 -17
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/quality/scorecard.md +11 -11
- mempalace_code-1.14.2/docs/quality/upstream-comparison.json +415 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/release-admission-rulesets.md +1 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/agent_plugin/plugin.json +1 -1
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/cli.py +18 -2
- mempalace_code-1.14.2/mempalace_code/cli_commands/wing_migration.py +12 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/entity_registry.py +30 -191
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp/dispatch.py +66 -26
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp/tools/search.py +10 -3
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mining/orchestrator.py +134 -31
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mining/projects.py +10 -1
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/normalize.py +4 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/search_reranker.py +22 -12
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/searcher.py +23 -8
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/storage.py +175 -41
- mempalace_code-1.14.2/mempalace_code/wing_migration.py +5398 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/pyproject.toml +1 -1
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/docs_drift_guard.py +6 -6
- mempalace_code-1.14.2/scripts/pytest_failure_summary.py +83 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/release_admission_checks.py +45 -12
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/release_readiness_gate.py +22 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/upstream_comparison_guard.py +2 -2
- mempalace_code-1.14.2/scripts/wing_migration.py +7 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_cli_command_modules.py +2 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_code_retrieval_bench.py +295 -30
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_convo_miner.py +31 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_docs_drift_guard.py +6 -7
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_e2e.py +4 -1
- mempalace_code-1.14.2/tests/test_entity_registry.py +251 -0
- mempalace_code-1.14.2/tests/test_explicit_wing_consistency.py +263 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_mcp_server.py +57 -0
- mempalace_code-1.14.2/tests/test_mine_source_exact.py +188 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_miner.py +332 -16
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_normalize.py +32 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_packaging_namespace.py +23 -0
- mempalace_code-1.14.2/tests/test_pytest_failure_summary.py +68 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_release_preflight.py +1 -1
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_release_readiness_gate.py +12 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_release_ruleset_contract.py +48 -2
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_release_workflow_admission.py +48 -2
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_search_reranker.py +32 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_searcher.py +232 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_storage.py +314 -1
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_upstream_comparison_guard.py +28 -21
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_watcher.py +1 -1
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_watcher_resource_subprocess.py +23 -11
- mempalace_code-1.14.2/tests/test_wing_migration.py +3302 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/uv.lock +1 -1
- mempalace_code-1.13.8/docs/UPSTREAM_COMPARISON.md +0 -272
- mempalace_code-1.13.8/docs/quality/upstream-comparison.json +0 -316
- mempalace_code-1.13.8/tests/test_entity_registry.py +0 -133
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/.gitignore +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/.gitleaks.toml +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/.pre-commit-config.yaml +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/AGENTS.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/CLAUDE.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/CONTRIBUTING.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/LICENSE +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/NOTICE +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/assets/mempalace_banner.jpg +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/BENCHMARKS.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/HYBRID_MODE.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/README.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/convomem_bench.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/demo_perf_budgets.json +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/demo_perf_budgets.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/dotnet_bench.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/embed_ab_bench.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/locomo_bench.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/longmemeval_bench.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/membench_bench.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/minilm_runtime_compatibility_fixture.json +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/results_embed_ab_2026-04-09.json +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/results_token_delta_mempalace.json +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/retrieval_quality_facts.json +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/token_delta_bench.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/benchmarks/token_delta_fixture_facts.json +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/AGENT_INSTALL.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/BACKUP_RESTORE.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/BENCH_TOKEN_DELTA.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/COMPARISON_GRAPHIFY.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/DEPENDENCY_UPGRADE_GATE.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/HOW_SEARCH_WORKS.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/LLM_USAGE_RULES.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/UPDATES.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/UPSTREAM_HARDENING.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/WHY_THIS_FORK.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/demo/code-intelligence-packet.json +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/demo/code-intelligence-packet.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/dependency-audit-allowlist.json +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/quality/PALACE-SCOPE-RESOURCE-BOUNDARY.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/quality/README.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/quality/autopilot-demo-gate-ledger.json +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/quality/autopilot-demo-gate-ledger.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/quality/workflow-review-protocol.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/docs/refactoring/REFAC-MINER-MODULES/progress.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/examples/HOOKS_TUTORIAL.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/examples/basic_mining.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/examples/convo_import.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/examples/gemini_cli_setup.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/examples/mcp_setup.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/hooks/README.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/hooks/mempal_precompact_hook.sh +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/hooks/mempal_save_hook.sh +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace/__init__.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace/mcp_server.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/README.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/__init__.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/__main__.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/_stdio.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/agent_plugin/mcp.json +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/agent_plugin/schemas/1.0.0/mcp.schema.json +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/agent_plugin/schemas/1.0.0/plugin.schema.json +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/agent_plugin/schemas/SCHEMA-NOTICE.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/agent_plugin/skills/mempalace/SKILL.md +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/agent_plugins.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/architecture.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/backup.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/cli_commands/__init__.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/cli_commands/agent_plugin.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/cli_commands/alias.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/cli_commands/backup_restore.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/cli_commands/common.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/cli_commands/diary.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/cli_commands/export_import.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/cli_commands/ingest.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/cli_commands/maintenance.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/cli_commands/model.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/cli_commands/preflight.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/cli_commands/query.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/cli_commands/update.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/cli_commands/version_check.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/cli_commands/watch.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/config.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/convo_miner.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/dialect.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/disk_budget.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/entity_detector.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/export.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/general_extractor.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/knowledge_graph.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/language_catalog.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/layers.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp/__init__.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp/protocol_compat.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp/protocol_text.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp/registry.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp/runtime.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp/tools/__init__.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp/tools/architecture.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp/tools/diary.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp/tools/graph.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp/tools/kg.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp/tools/read.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp/tools/write.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp_launcher.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp_server.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mcp_tool_profiles.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/miner.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mining/__init__.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mining/batching.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mining/chunkers.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mining/kg_extract.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mining/languages.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mining/scanner.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mining/symbols.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/mirror_preflight.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/onboarding.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/operation_lock.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/palace_graph.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/py.typed +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/reader.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/retrieval_rerank.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/room_detector_local.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/source_io.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/spellcheck.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/split_mega_files.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/taxonomy_filters.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/treesitter.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/updater.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/version.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/version_check.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/mempalace_code/watcher.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/pyrightconfig.strict.json +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/architecture_guard.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/bootstrap.sh +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/dependency_upgrade_gate.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/gate_inventory.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/gen_code_intelligence_packet.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/gitleaks_scan.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/nuke_wing.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/public_safety_scan.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/quality_scorecard.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/release_artifact_gate.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/release_install_metadata_smoke.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/release_preflight.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/release_public_read.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/release_status_gate.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/scripts/workflow_summary_guard.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/conftest.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/fixtures/unreasoned_suppression.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/release_smoke_support.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_agent_plugin_package.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_agent_skill_authority_contract.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_architecture_extraction.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_architecture_guard.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_autopilot_demo_gate_ledger.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_backup.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_backup_cli.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_chunking.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_cli.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_cli_golden_scenarios.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_code_intelligence_packet.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_config.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_demo_perf_budgets.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_dependency_upgrade_gate.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_dialect.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_disk_budget.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_dotnet_bench.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_dotnet_config.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_embed_ab_bench.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_embedding_runtime.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_entity_detector.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_export.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_gate_inventory.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_general_extractor.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_gitleaks_scan.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_installed_artifact_behavior.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_installed_cli_palace_scope.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_kg_extract.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_knowledge_graph.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_lang_detect.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_language_catalog.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_layers.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_mcp_protocol_compat.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_mcp_registry.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_mcp_tool_profiles.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_miner_modules.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_offline.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_onboarding.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_operation_lock.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_palace_graph.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_palace_scope_resource_boundary.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_public_safety_scan.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_pyright_optional_dependencies.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_quality_palace_scope_resource_boundary.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_quality_scorecard.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_reader.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_regular_source_guard.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_release_artifact_gate.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_release_install_metadata_smoke.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_release_public_read.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_release_skill_contract.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_release_status_gate.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_retrieval_rerank.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_split_mega_files.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_stdio.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_storage_lance.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_symbol_extract.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_taxonomy_filters.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_token_delta_bench.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_treesitter.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_type_suppressions.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_updater.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_version_check.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_version_consistency.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_watcher_resource_bounds.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tests/test_workflow_summary_guard.py +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tools/gitleaks/go.mod +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tools/gitleaks/go.sum +0 -0
- {mempalace_code-1.13.8 → mempalace_code-1.14.2}/tools/gitleaks/tools.go +0 -0
|
@@ -2,6 +2,79 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## v1.14.2 — 2026-09-21
|
|
6
|
+
|
|
7
|
+
Recovery release for the accumulated v1.14.1 changes. The immutable v1.14.1
|
|
8
|
+
tag stopped before artifact build when the pinned upstream head moved, so no
|
|
9
|
+
v1.14.1 package or GitHub Release exists.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Refreshed the reviewed upstream snapshot through `e038af97`; the MCP import
|
|
14
|
+
fix already has an equivalent entry-point boundary in this fork, while the
|
|
15
|
+
upstream sync identity and JSON audit-WAL changes belong to unsupported
|
|
16
|
+
runtime owners.
|
|
17
|
+
- Added the failed v1.14.1 tag to the immutable orphan-tag evidence registry.
|
|
18
|
+
- Kept the live upstream check at the canonical pre-tag boundary so later
|
|
19
|
+
upstream movement cannot strand another immutable public tag.
|
|
20
|
+
|
|
21
|
+
## v1.14.1 — 2026-09-20 (tagged, not published)
|
|
22
|
+
|
|
23
|
+
The tag remains immutable public evidence. Publication stopped before artifact
|
|
24
|
+
build because the reviewed upstream head changed; these changes ship in v1.14.2.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Wing migration now binds live evidence to the qualified runner, updates the
|
|
29
|
+
destination runtime hash after the merge, bounds retained qualification storage,
|
|
30
|
+
and preserves exact recovery for the original v16 receipt.
|
|
31
|
+
- Wing migration receipts use the owner-controlled rule `retain until verified
|
|
32
|
+
recovery or owner disposition`; the obsolete calendar deadline is rejected before
|
|
33
|
+
any evidence or migration state is written.
|
|
34
|
+
- Installed-wheel qualification now treats the installation-wide MCP lock files as
|
|
35
|
+
stable protected anchors and directly exercises the `wing-migration` CLI refusal
|
|
36
|
+
without an action.
|
|
37
|
+
- Runtime provenance checks now accept platform-managed symlink ancestors outside
|
|
38
|
+
the owned installation and source roots while still refusing symlinks inside them.
|
|
39
|
+
|
|
40
|
+
## v1.14.0 — 2026-09-18
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
44
|
+
- Added the installed wing migration operator with exact-union, snapshot, retry,
|
|
45
|
+
and recovery qualification. Synthetic mining uses an independent offline copy of
|
|
46
|
+
the validated canonical model cache. Exact-host live authority adds MCP maintenance
|
|
47
|
+
fencing, retained recovery evidence, and an original-path zero-write runtime check.
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- Code retrieval qualification now checks current declaration owners and same-hit
|
|
52
|
+
symbols across storage, default code search, and hybrid code search while exposing
|
|
53
|
+
additive ranking evidence.
|
|
54
|
+
- Configured non-.NET wing identifiers now preserve hyphens consistently across
|
|
55
|
+
standalone mining, mine-all, and fresh watcher startup. Git/folder-derived names,
|
|
56
|
+
.NET solution precedence, explicit CLI overrides, historical rows, and active
|
|
57
|
+
watcher snapshots retain their existing behavior.
|
|
58
|
+
|
|
59
|
+
### Fixed
|
|
60
|
+
|
|
61
|
+
- Recognized Codex rollout files that contain no complete supported conversation now fail before
|
|
62
|
+
raw JSON can be filed as memory and remain eligible for retry after the transcript completes.
|
|
63
|
+
- Entity-registry atomic saves now bound temporary-name collision retries and surface directory
|
|
64
|
+
permission failures immediately on every supported Python version.
|
|
65
|
+
- Existing entity registries with malformed JSON, a non-object root, or a read failure now stop
|
|
66
|
+
before onboarding or programmatic setup can replace their non-regenerable contents.
|
|
67
|
+
- Stale-file deletion and dependent knowledge-graph and tiny-hash expiry now require
|
|
68
|
+
proven regenerable sources owned by the selected project.
|
|
69
|
+
- Full-copy wing qualification now removes each recovered descendant trial before creating the
|
|
70
|
+
next one, caps retained baseline snapshots at one, and refuses stale trial or snapshot
|
|
71
|
+
generations before writing new evidence.
|
|
72
|
+
|
|
73
|
+
### Security
|
|
74
|
+
|
|
75
|
+
- Removed the unused Wikipedia lookup API from the entity registry. Legacy cached entries remain
|
|
76
|
+
readable, while current packages contain no unconfigured entity-research network path.
|
|
77
|
+
|
|
5
78
|
## v1.13.8 — 2026-09-02
|
|
6
79
|
|
|
7
80
|
Recovery release for the accumulated v1.13.7 changes. The immutable v1.13.7
|
|
@@ -882,7 +955,7 @@ Add 4 architecture-oriented MCP tools for .NET type analysis: `mempalace_find_im
|
|
|
882
955
|
|
|
883
956
|
## 2026-04-17 · SKILLS-HOOKS
|
|
884
957
|
|
|
885
|
-
Add Claude Code skills and hooks
|
|
958
|
+
Add Claude Code skills and hooks: 12 skills (`/start`, `/status`, `/verify`, `/palace-health`, `/task-plan`, `/task-hardening`, `/doc-refresh`, `/ship`, `/release`, `/entropy-gc`, `/mine`, `/bench`), 3 shared modules (mode-classification, task-state, commit-checkpoint), Codex review integration, pre-commit verification gate, and edit logging hooks.
|
|
886
959
|
|
|
887
960
|
## 2026-04-17 · BENCH-DOTNET
|
|
888
961
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: mempalace-code
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.14.2
|
|
4
4
|
Summary: Developer memory tool — mine codebases and conversations into a LanceDB-backed searchable palace. No API key required.
|
|
5
5
|
Project-URL: Homepage, https://github.com/rergards/mempalace-code
|
|
6
6
|
Project-URL: Repository, https://github.com/rergards/mempalace-code
|
|
@@ -1180,6 +1180,7 @@ mempalace-code version-check # show version-check stat
|
|
|
1180
1180
|
mempalace-code version-check --check-now # check PyPI now; prints a pip fallback for unmanaged installs
|
|
1181
1181
|
mempalace-code update status # inspect upgrade eligibility (supported installs)
|
|
1182
1182
|
mempalace-code agent-plugin path --json # locate the installed Agent Plugins package directory
|
|
1183
|
+
mempalace-code wing-migration qualify --mode synthetic # qualify the receipt-bound copy migration operator
|
|
1183
1184
|
```
|
|
1184
1185
|
|
|
1185
1186
|
Plain `status` prints a full wing/room breakdown, so its output grows with palace size. Do not use it as a routine agent bootstrap or machine-readable health check; use `status --summary` for bounded shell-based CLI discovery, task-specific MCP retrieval, or `mempalace-code health --json` for a compact CLI integrity report.
|
|
@@ -1275,7 +1276,7 @@ python -m pyright --pythonpath "$(python -c 'import sys; print(sys.executable)')
|
|
|
1275
1276
|
Apache 2.0 — see [LICENSE](LICENSE) and [NOTICE](NOTICE).
|
|
1276
1277
|
|
|
1277
1278
|
<!-- Link Definitions -->
|
|
1278
|
-
[version-shield]: https://img.shields.io/badge/version-1.
|
|
1279
|
+
[version-shield]: https://img.shields.io/badge/version-1.14.2-4dc9f6?style=flat-square&labelColor=0a0e14
|
|
1279
1280
|
[release-link]: https://github.com/rergards/mempalace-code/releases
|
|
1280
1281
|
[python-shield]: https://img.shields.io/badge/python-3.11+-7dd8f8?style=flat-square&labelColor=0a0e14&logo=python&logoColor=7dd8f8
|
|
1281
1282
|
[python-link]: https://www.python.org/
|
|
@@ -1121,6 +1121,7 @@ mempalace-code version-check # show version-check stat
|
|
|
1121
1121
|
mempalace-code version-check --check-now # check PyPI now; prints a pip fallback for unmanaged installs
|
|
1122
1122
|
mempalace-code update status # inspect upgrade eligibility (supported installs)
|
|
1123
1123
|
mempalace-code agent-plugin path --json # locate the installed Agent Plugins package directory
|
|
1124
|
+
mempalace-code wing-migration qualify --mode synthetic # qualify the receipt-bound copy migration operator
|
|
1124
1125
|
```
|
|
1125
1126
|
|
|
1126
1127
|
Plain `status` prints a full wing/room breakdown, so its output grows with palace size. Do not use it as a routine agent bootstrap or machine-readable health check; use `status --summary` for bounded shell-based CLI discovery, task-specific MCP retrieval, or `mempalace-code health --json` for a compact CLI integrity report.
|
|
@@ -1216,7 +1217,7 @@ python -m pyright --pythonpath "$(python -c 'import sys; print(sys.executable)')
|
|
|
1216
1217
|
Apache 2.0 — see [LICENSE](LICENSE) and [NOTICE](NOTICE).
|
|
1217
1218
|
|
|
1218
1219
|
<!-- Link Definitions -->
|
|
1219
|
-
[version-shield]: https://img.shields.io/badge/version-1.
|
|
1220
|
+
[version-shield]: https://img.shields.io/badge/version-1.14.2-4dc9f6?style=flat-square&labelColor=0a0e14
|
|
1220
1221
|
[release-link]: https://github.com/rergards/mempalace-code/releases
|
|
1221
1222
|
[python-shield]: https://img.shields.io/badge/python-3.11+-7dd8f8?style=flat-square&labelColor=0a0e14&logo=python&logoColor=7dd8f8
|
|
1222
1223
|
[python-link]: https://www.python.org/
|
|
@@ -9,7 +9,9 @@ file-level retrieval quality for naive, smart, and tree-sitter chunking.
|
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
11
|
import argparse
|
|
12
|
+
import ast
|
|
12
13
|
import contextlib
|
|
14
|
+
import gc
|
|
13
15
|
import hashlib
|
|
14
16
|
import importlib
|
|
15
17
|
import importlib.metadata
|
|
@@ -37,10 +39,19 @@ if not _COMPATIBILITY_MODE_REQUESTED:
|
|
|
37
39
|
sys.path.insert(0, str(_PROJECT_ROOT))
|
|
38
40
|
|
|
39
41
|
import mempalace_code.miner as miner # noqa: E402
|
|
42
|
+
import mempalace_code.mining.chunkers as mining_chunkers # noqa: E402
|
|
43
|
+
import mempalace_code.searcher as searcher # noqa: E402
|
|
40
44
|
from mempalace_code.storage import DEFAULT_EMBED_MODEL, open_store # noqa: E402
|
|
41
45
|
from mempalace_code.version import __version__ # noqa: E402
|
|
42
46
|
|
|
43
47
|
SUPPORTED_MODES = ("naive", "smart", "treesitter")
|
|
48
|
+
SEARCH_PATHS = ("store.query", "code_search", "code_search_hybrid")
|
|
49
|
+
PATH_CANDIDATE_LIMITS = {
|
|
50
|
+
"store.query": 10,
|
|
51
|
+
"code_search": 30,
|
|
52
|
+
"code_search_hybrid": 50,
|
|
53
|
+
}
|
|
54
|
+
REPORT_SCHEMA_VERSION = 2
|
|
44
55
|
DEFAULT_DATASET = Path(__file__).resolve().parent / "data" / "code_retrieval_queries.json"
|
|
45
56
|
NAIVE_WINDOW_LINES = 80
|
|
46
57
|
NAIVE_OVERLAP_LINES = 10
|
|
@@ -379,7 +390,8 @@ def load_dataset(path: Path, limit: int | None = None) -> list[dict]:
|
|
|
379
390
|
if not records:
|
|
380
391
|
raise BenchError("dataset must contain at least one record")
|
|
381
392
|
|
|
382
|
-
required = {"id", "query", "expected_files", "category"}
|
|
393
|
+
required = {"id", "query", "expected_files", "category", "match_kind"}
|
|
394
|
+
seen_ids = set()
|
|
383
395
|
for idx, record in enumerate(records):
|
|
384
396
|
if not isinstance(record, dict):
|
|
385
397
|
raise BenchError(f"dataset record {idx} must be an object")
|
|
@@ -388,6 +400,9 @@ def load_dataset(path: Path, limit: int | None = None) -> list[dict]:
|
|
|
388
400
|
raise BenchError(f"dataset record {idx} is missing: {', '.join(missing)}")
|
|
389
401
|
if not isinstance(record["id"], str) or not record["id"]:
|
|
390
402
|
raise BenchError(f"dataset record {idx} id must be a non-empty string")
|
|
403
|
+
if record["id"] in seen_ids:
|
|
404
|
+
raise BenchError(f"dataset record {record['id']} has a duplicate id")
|
|
405
|
+
seen_ids.add(record["id"])
|
|
391
406
|
if not isinstance(record["query"], str) or not record["query"]:
|
|
392
407
|
raise BenchError(f"dataset record {record['id']} query must be a non-empty string")
|
|
393
408
|
if not isinstance(record["category"], str) or not record["category"]:
|
|
@@ -401,6 +416,30 @@ def load_dataset(path: Path, limit: int | None = None) -> list[dict]:
|
|
|
401
416
|
raise BenchError(
|
|
402
417
|
f"dataset record {record['id']} expected_files must be a non-empty list of strings"
|
|
403
418
|
)
|
|
419
|
+
if len(set(expected_files)) != len(expected_files):
|
|
420
|
+
raise BenchError(f"dataset record {record['id']} expected_files must be unique")
|
|
421
|
+
match_kind = record["match_kind"]
|
|
422
|
+
if match_kind not in {"symbol", "file_only"}:
|
|
423
|
+
raise BenchError(
|
|
424
|
+
f"dataset record {record['id']} match_kind must be 'symbol' or 'file_only'"
|
|
425
|
+
)
|
|
426
|
+
expected_symbols = record.get("expected_symbols")
|
|
427
|
+
if match_kind == "symbol":
|
|
428
|
+
if (
|
|
429
|
+
not isinstance(expected_symbols, list)
|
|
430
|
+
or not expected_symbols
|
|
431
|
+
or any(not isinstance(symbol, str) or not symbol for symbol in expected_symbols)
|
|
432
|
+
):
|
|
433
|
+
raise BenchError(
|
|
434
|
+
f"dataset record {record['id']} expected_symbols must be a non-empty list "
|
|
435
|
+
"of strings for symbol matches"
|
|
436
|
+
)
|
|
437
|
+
if len(set(expected_symbols)) != len(expected_symbols):
|
|
438
|
+
raise BenchError(f"dataset record {record['id']} expected_symbols must be unique")
|
|
439
|
+
elif "expected_symbols" in record:
|
|
440
|
+
raise BenchError(
|
|
441
|
+
f"dataset record {record['id']} file_only matches must omit expected_symbols"
|
|
442
|
+
)
|
|
404
443
|
return records
|
|
405
444
|
|
|
406
445
|
|
|
@@ -421,22 +460,37 @@ def _source_identity(source_file: str) -> tuple[str, str]:
|
|
|
421
460
|
|
|
422
461
|
|
|
423
462
|
def file_matches_expected(source_file: str, expected_file: str) -> bool:
|
|
424
|
-
"""Match
|
|
463
|
+
"""Match a basename or complete normalized path suffix on segment boundaries."""
|
|
425
464
|
source, basename = _source_identity(source_file)
|
|
426
|
-
expected = expected_file.replace("\\", "/")
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
465
|
+
expected = expected_file.replace("\\", "/").strip("/")
|
|
466
|
+
if "/" not in expected:
|
|
467
|
+
return basename == expected
|
|
468
|
+
return source == expected or source.endswith(f"/{expected}")
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def hit_at_k(
|
|
472
|
+
metadatas: list[dict],
|
|
473
|
+
expected_files: list[str],
|
|
474
|
+
k: int,
|
|
475
|
+
expected_symbols: list[str] | None = None,
|
|
476
|
+
) -> bool:
|
|
431
477
|
"""Return True when any expected file appears within top-k result metadata."""
|
|
432
|
-
return rank_of_first_hit(metadatas[:k], expected_files) is not None
|
|
478
|
+
return rank_of_first_hit(metadatas[:k], expected_files, expected_symbols) is not None
|
|
433
479
|
|
|
434
480
|
|
|
435
|
-
def rank_of_first_hit(
|
|
436
|
-
|
|
481
|
+
def rank_of_first_hit(
|
|
482
|
+
metadatas: list[dict],
|
|
483
|
+
expected_files: list[str],
|
|
484
|
+
expected_symbols: list[str] | None = None,
|
|
485
|
+
) -> int | None:
|
|
486
|
+
"""Return the first same-hit file and optional exact-symbol match."""
|
|
437
487
|
for rank, meta in enumerate(metadatas, start=1):
|
|
438
488
|
source_file = meta.get("source_file", "")
|
|
439
|
-
|
|
489
|
+
file_match = any(
|
|
490
|
+
file_matches_expected(source_file, expected) for expected in expected_files
|
|
491
|
+
)
|
|
492
|
+
symbol_match = expected_symbols is None or meta.get("symbol_name") in expected_symbols
|
|
493
|
+
if file_match and symbol_match:
|
|
440
494
|
return rank
|
|
441
495
|
return None
|
|
442
496
|
|
|
@@ -447,16 +501,50 @@ def scan_corpus_files(repo_dir: Path) -> list[Path]:
|
|
|
447
501
|
|
|
448
502
|
|
|
449
503
|
def validate_dataset(repo_dir: Path, records: list[dict]) -> int:
|
|
450
|
-
"""Validate
|
|
504
|
+
"""Validate expected paths and Python declarations against the current corpus."""
|
|
451
505
|
scanned = [str(path.relative_to(repo_dir)) for path in scan_corpus_files(repo_dir)]
|
|
452
506
|
failures = []
|
|
453
507
|
for record in records:
|
|
508
|
+
resolved_files = []
|
|
454
509
|
for expected in record["expected_files"]:
|
|
455
|
-
|
|
510
|
+
matches = [source for source in scanned if file_matches_expected(source, expected)]
|
|
511
|
+
if not matches:
|
|
456
512
|
failures.append((record["id"], expected))
|
|
457
513
|
print(f"FAIL {record['id']}: missing {expected}")
|
|
458
514
|
else:
|
|
515
|
+
resolved_files.extend(matches)
|
|
459
516
|
print(f"PASS {record['id']}: {expected}")
|
|
517
|
+
if record["match_kind"] == "symbol" and resolved_files:
|
|
518
|
+
declared = set()
|
|
519
|
+
for source in resolved_files:
|
|
520
|
+
path = repo_dir / source
|
|
521
|
+
if path.suffix != ".py":
|
|
522
|
+
continue
|
|
523
|
+
try:
|
|
524
|
+
tree = ast.parse(path.read_text(encoding="utf-8", errors="replace"))
|
|
525
|
+
except (OSError, SyntaxError) as exc:
|
|
526
|
+
failures.append((record["id"], f"unreadable declaration owner: {source}"))
|
|
527
|
+
print(f"FAIL {record['id']}: cannot parse declarations in {source}: {exc}")
|
|
528
|
+
continue
|
|
529
|
+
declared.update(
|
|
530
|
+
node.name
|
|
531
|
+
for node in ast.walk(tree)
|
|
532
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef))
|
|
533
|
+
)
|
|
534
|
+
missing_symbols = [
|
|
535
|
+
symbol for symbol in record["expected_symbols"] if symbol not in declared
|
|
536
|
+
]
|
|
537
|
+
if len(missing_symbols) == len(record["expected_symbols"]):
|
|
538
|
+
failures.append((record["id"], "expected declaration"))
|
|
539
|
+
print(
|
|
540
|
+
f"FAIL {record['id']}: no expected declaration in owner files: "
|
|
541
|
+
f"{', '.join(record['expected_symbols'])}"
|
|
542
|
+
)
|
|
543
|
+
else:
|
|
544
|
+
print(
|
|
545
|
+
f"PASS {record['id']}: declaration "
|
|
546
|
+
f"{', '.join(symbol for symbol in record['expected_symbols'] if symbol in declared)}"
|
|
547
|
+
)
|
|
460
548
|
if failures:
|
|
461
549
|
return 1
|
|
462
550
|
print(f"PASS dataset: {len(records)} queries")
|
|
@@ -469,12 +557,12 @@ def smart_chunking_only(enabled: bool):
|
|
|
469
557
|
if not enabled:
|
|
470
558
|
yield
|
|
471
559
|
return
|
|
472
|
-
original =
|
|
473
|
-
|
|
560
|
+
original = mining_chunkers.get_parser
|
|
561
|
+
mining_chunkers.get_parser = lambda _language: None
|
|
474
562
|
try:
|
|
475
563
|
yield
|
|
476
564
|
finally:
|
|
477
|
-
|
|
565
|
+
mining_chunkers.get_parser = original
|
|
478
566
|
|
|
479
567
|
|
|
480
568
|
def _repo_commit(repo_dir: Path) -> str | None:
|
|
@@ -605,26 +693,58 @@ def mine_mode(repo_dir: Path, palace_path: Path, mode: str):
|
|
|
605
693
|
return mine_with_miner(repo_dir, palace_path, mode)
|
|
606
694
|
|
|
607
695
|
|
|
608
|
-
def
|
|
609
|
-
|
|
610
|
-
latencies = []
|
|
611
|
-
for record in records:
|
|
612
|
-
t0 = time.time()
|
|
696
|
+
def _query_path(store, palace_path: Path, record: dict, path: str) -> list[dict]:
|
|
697
|
+
if path == "store.query":
|
|
613
698
|
results = store.query(
|
|
614
699
|
query_texts=[record["query"]],
|
|
615
700
|
n_results=10,
|
|
616
701
|
include=["documents", "metadatas", "distances"],
|
|
617
702
|
)
|
|
703
|
+
return results.get("metadatas", [[]])[0] if results.get("metadatas") else []
|
|
704
|
+
|
|
705
|
+
rerank = "hybrid" if path == "code_search_hybrid" else None
|
|
706
|
+
results = searcher.code_search(str(palace_path), record["query"], n_results=10, rerank=rerank)
|
|
707
|
+
if "error" in results:
|
|
708
|
+
raise BenchError(f"{path} failed for {record['id']}: {results['error']}")
|
|
709
|
+
return results.get("results", [])
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
@contextlib.contextmanager
|
|
713
|
+
def supported_search_store(store):
|
|
714
|
+
"""Route supported code_search calls to the lifecycle-owned benchmark store."""
|
|
715
|
+
original = searcher.open_store
|
|
716
|
+
|
|
717
|
+
def use_existing_store(*_args, **_kwargs):
|
|
718
|
+
return store
|
|
719
|
+
|
|
720
|
+
searcher.open_store = use_existing_store
|
|
721
|
+
try:
|
|
722
|
+
yield
|
|
723
|
+
finally:
|
|
724
|
+
searcher.open_store = original
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
def run_queries(
|
|
728
|
+
store, palace_path: Path, records: list[dict], path: str
|
|
729
|
+
) -> tuple[list[dict], list[float]]:
|
|
730
|
+
"""Evaluate one supported retrieval path without hiding errors or misses."""
|
|
731
|
+
per_query = []
|
|
732
|
+
latencies = []
|
|
733
|
+
for record in records:
|
|
734
|
+
t0 = time.time()
|
|
735
|
+
metas = _query_path(store, palace_path, record, path)
|
|
618
736
|
latencies.append((time.time() - t0) * 1000)
|
|
619
|
-
|
|
620
|
-
rank = rank_of_first_hit(metas, record["expected_files"])
|
|
737
|
+
symbols = record["expected_symbols"] if record["match_kind"] == "symbol" else None
|
|
738
|
+
rank = rank_of_first_hit(metas, record["expected_files"], symbols)
|
|
621
739
|
per_query.append(
|
|
622
740
|
{
|
|
623
741
|
"id": record["id"],
|
|
624
742
|
"query": record["query"],
|
|
625
743
|
"category": record["category"],
|
|
626
744
|
"expected_files": record["expected_files"],
|
|
627
|
-
"
|
|
745
|
+
"match_kind": record["match_kind"],
|
|
746
|
+
"expected_symbols": record.get("expected_symbols"),
|
|
747
|
+
"path": path,
|
|
628
748
|
"rank": rank,
|
|
629
749
|
"hit_at_5": rank is not None and rank <= 5,
|
|
630
750
|
"hit_at_10": rank is not None and rank <= 10,
|
|
@@ -636,55 +756,61 @@ def run_queries(store, records: list[dict]) -> tuple[list[dict], list[float]]:
|
|
|
636
756
|
|
|
637
757
|
|
|
638
758
|
def aggregate_results(per_query: list[dict], latencies: list[float]) -> dict:
|
|
639
|
-
|
|
640
|
-
r5 = sum(1 for row in per_query if row["hit_at_5"]) / query_count
|
|
641
|
-
r10 = sum(1 for row in per_query if row["hit_at_10"]) / query_count
|
|
642
|
-
mrr = sum(1 / row["rank"] for row in per_query if row["rank"]) / query_count
|
|
643
|
-
|
|
644
|
-
by_category = defaultdict(list)
|
|
645
|
-
for row in per_query:
|
|
646
|
-
by_category[row["category"]].append(row)
|
|
647
|
-
|
|
648
|
-
per_category = {}
|
|
649
|
-
for category, rows in sorted(by_category.items()):
|
|
759
|
+
def summarize(rows: list[dict]) -> dict:
|
|
650
760
|
count = len(rows)
|
|
651
|
-
|
|
761
|
+
if not count:
|
|
762
|
+
return {"query_count": 0, "R@5": None, "R@10": None, "MRR": None}
|
|
763
|
+
return {
|
|
652
764
|
"query_count": count,
|
|
653
765
|
"R@5": sum(1 for row in rows if row["hit_at_5"]) / count,
|
|
654
766
|
"R@10": sum(1 for row in rows if row["hit_at_10"]) / count,
|
|
655
767
|
"MRR": sum(1 / row["rank"] for row in rows if row["rank"]) / count,
|
|
656
768
|
}
|
|
657
769
|
|
|
770
|
+
by_category = defaultdict(list)
|
|
771
|
+
for row in per_query:
|
|
772
|
+
by_category[row["category"]].append(row)
|
|
658
773
|
return {
|
|
659
|
-
"R@5": r5,
|
|
660
|
-
"R@10": r10,
|
|
661
|
-
"MRR": mrr,
|
|
662
774
|
"query_latency_avg_ms": sum(latencies) / len(latencies) if latencies else 0.0,
|
|
663
|
-
"
|
|
775
|
+
"populations": {
|
|
776
|
+
kind: summarize([row for row in per_query if row["match_kind"] == kind])
|
|
777
|
+
for kind in ("symbol", "file_only")
|
|
778
|
+
},
|
|
779
|
+
"per_category": {
|
|
780
|
+
category: summarize(rows) for category, rows in sorted(by_category.items())
|
|
781
|
+
},
|
|
664
782
|
}
|
|
665
783
|
|
|
666
784
|
|
|
667
785
|
def run_mode(repo_dir: Path, mode: str, records: list[dict]) -> dict:
|
|
668
786
|
tmp_dir = Path(tempfile.mkdtemp(prefix=f"code_bench_{mode}_"))
|
|
787
|
+
store = None
|
|
669
788
|
try:
|
|
670
789
|
t0 = time.time()
|
|
671
790
|
store, chunk_count, mode_meta = mine_mode(repo_dir, tmp_dir, mode)
|
|
672
791
|
embed_time_s = time.time() - t0
|
|
673
|
-
|
|
674
|
-
|
|
792
|
+
paths = {}
|
|
793
|
+
with supported_search_store(store):
|
|
794
|
+
for path in SEARCH_PATHS:
|
|
795
|
+
per_query, latencies = run_queries(store, tmp_dir, records, path)
|
|
796
|
+
metrics = aggregate_results(per_query, latencies)
|
|
797
|
+
paths[path] = {
|
|
798
|
+
"ordering": "storage-ranked" if path != "code_search_hybrid" else "hybrid",
|
|
799
|
+
"requested_results": 10,
|
|
800
|
+
"candidate_fetch_limit": PATH_CANDIDATE_LIMITS[path],
|
|
801
|
+
**metrics,
|
|
802
|
+
"per_query": per_query,
|
|
803
|
+
}
|
|
675
804
|
return {
|
|
676
805
|
"chunk_count": chunk_count,
|
|
677
806
|
"embed_time_s": embed_time_s,
|
|
678
807
|
"index_size_mb": _index_size_mb(tmp_dir),
|
|
679
|
-
"
|
|
680
|
-
"R@5": metrics["R@5"],
|
|
681
|
-
"R@10": metrics["R@10"],
|
|
682
|
-
"MRR": metrics["MRR"],
|
|
683
|
-
"per_category": metrics["per_category"],
|
|
684
|
-
"per_query": per_query,
|
|
808
|
+
"paths": paths,
|
|
685
809
|
**mode_meta,
|
|
686
810
|
}
|
|
687
811
|
finally:
|
|
812
|
+
store = None
|
|
813
|
+
gc.collect()
|
|
688
814
|
shutil.rmtree(tmp_dir, ignore_errors=True)
|
|
689
815
|
|
|
690
816
|
|
|
@@ -692,26 +818,31 @@ def build_comparison(modes: dict) -> dict:
|
|
|
692
818
|
"""Build compact table-friendly comparison metrics."""
|
|
693
819
|
return {
|
|
694
820
|
mode: {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
821
|
+
path: {
|
|
822
|
+
"symbol": result["paths"][path]["populations"]["symbol"],
|
|
823
|
+
"file_only": result["paths"][path]["populations"]["file_only"],
|
|
824
|
+
"query_latency_avg_ms": result["paths"][path]["query_latency_avg_ms"],
|
|
825
|
+
}
|
|
826
|
+
for path in SEARCH_PATHS
|
|
700
827
|
}
|
|
701
828
|
for mode, result in modes.items()
|
|
702
829
|
}
|
|
703
830
|
|
|
704
831
|
|
|
705
832
|
def print_table(modes: dict) -> None:
|
|
706
|
-
print("\nCode retrieval results")
|
|
707
|
-
print("mode
|
|
708
|
-
print("------------
|
|
833
|
+
print(f"\nCode retrieval results (schema={REPORT_SCHEMA_VERSION}, model={DEFAULT_EMBED_MODEL})")
|
|
834
|
+
print("mode path population count R@5 R@10 MRR")
|
|
835
|
+
print("------------ ------------------ ---------- ----- ----- ----- -----")
|
|
709
836
|
for mode, result in modes.items():
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
837
|
+
for path, path_result in result["paths"].items():
|
|
838
|
+
for population, metrics in path_result["populations"].items():
|
|
839
|
+
values = [metrics[name] for name in ("R@5", "R@10", "MRR")]
|
|
840
|
+
formatted = ["null" if value is None else f"{value:.3f}" for value in values]
|
|
841
|
+
print(
|
|
842
|
+
f"{mode:<12} {path:<18} {population:<10} "
|
|
843
|
+
f"{metrics['query_count']:>5} {formatted[0]:>5} "
|
|
844
|
+
f"{formatted[1]:>5} {formatted[2]:>5}"
|
|
845
|
+
)
|
|
715
846
|
|
|
716
847
|
|
|
717
848
|
def run_benchmark(repo_dir: Path, dataset_path: Path, modes: list[str], limit: int | None) -> dict:
|
|
@@ -719,6 +850,7 @@ def run_benchmark(repo_dir: Path, dataset_path: Path, modes: list[str], limit: i
|
|
|
719
850
|
mode_results = {mode: run_mode(repo_dir, mode, records) for mode in modes}
|
|
720
851
|
return {
|
|
721
852
|
"meta": {
|
|
853
|
+
"report_schema_version": REPORT_SCHEMA_VERSION,
|
|
722
854
|
"date": datetime.now(UTC).isoformat(),
|
|
723
855
|
"repo_path": str(repo_dir),
|
|
724
856
|
"repo_name": repo_dir.name,
|