kernel-lore-mcp 0.3.2__tar.gz → 0.3.3__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.
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/Cargo.lock +1 -1
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/Cargo.toml +1 -1
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/PKG-INFO +1 -1
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/pyproject.toml +1 -1
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/bin/sync.rs +74 -8
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/error.rs +3 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/__init__.py +1 -1
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/_core.pyi +8 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/cost_class.py +25 -2
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/health.py +29 -3
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/routes/status.py +16 -8
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/timeout.py +28 -2
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/lib.rs +2 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/python.rs +47 -1
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/reader.rs +6 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/router.rs +4 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/timeout.rs +99 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_cost_class.py +46 -22
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_resources_routes.py +14 -1
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/uv.lock +1 -1
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/.github/workflows/ci.yml +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/.github/workflows/release.yml +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/.gitignore +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/.python-version +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/CHANGELOG.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/CLAUDE.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/CONTRIBUTING.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/GOVERNANCE.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/LEGAL.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/LICENSE +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/README.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/SECURITY.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/TODO.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/README.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/architecture/data-flow.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/architecture/deployment-modes.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/architecture/four-tier-index.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/architecture/over-db.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/architecture/overview.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/architecture/reciprocity.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/architecture/trade-offs.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/demos/first-session.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/indexing/bm25-tier.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/indexing/compressed-store.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/indexing/metadata-tier.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/indexing/path-tier.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/indexing/tokenizer-spec.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/indexing/trigram-tier.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/ingestion/grokmirror.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/ingestion/mbox-parsing.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/ingestion/patch-parsing.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/ingestion/shard-walking.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/mcp/client-config.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/mcp/query-routing.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/mcp/tools.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/mcp/transport-auth.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/ops/corpus-coverage.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/ops/cost-model.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/ops/ec2-sizing.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/ops/monitoring.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/ops/production-hardening.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/ops/public-launch-checklist.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/ops/runbook.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/ops/threat-model.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/ops/update-cadence.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/ops/update-frequency.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/plans/2026-04-14-best-in-class-kernel-mcp.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/plans/2026-04-15-internalize-grokmirror.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/plans/2026-04-15-mcp-spec-coverage-and-uplift.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/plans/2026-04-17-overdb-followups.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/plans/2026-04-17-overdb-metadata-tier.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/plans/2026-04-20-v0.3.0-plan.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/plans/2026-04-22-v0.3.1-plan.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/research/2026-04-14-agent-ergonomics.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/research/2026-04-14-best-in-class-mcp-survey.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/research/2026-04-14-external-data-sources.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/research/2026-04-14-gix-vs-git2.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/research/2026-04-14-mcp-python-sdk.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/research/2026-04-14-pyo3-maturin.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/research/2026-04-14-search-library-landscape.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/research/2026-04-14-storage-footprint.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/research/2026-04-14-tantivy.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/research/2026-04-14-workflow-gap-analysis.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/research/2026-04-15-fuzzy-search-design.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/research/2026-04-15-path-mentions.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/research/2026-04-17-overdb-validation.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/research/training-retriever.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/README.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/checklists/01-research.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/checklists/02-design.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/checklists/03-implement.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/checklists/04-test.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/checklists/05-quality.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/checklists/06-review.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/checklists/07-commit.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/checklists/08-debug.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/checklists/09-optimize.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/checklists/10-document.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/checklists/index.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/code-quality.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/data-structures.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/design/boundaries.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/design/concurrency.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/design/dependencies.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/design/errors.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/design/modules.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/git.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/index.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/language.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/libraries/fastmcp.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/libraries/httpx.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/libraries/pydantic.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/libraries/structlog.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/naming.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/pyo3-maturin.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/testing.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/python/uv.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/cargo.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/checklists/01-research.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/checklists/02-design.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/checklists/03-implement.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/checklists/04-test.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/checklists/05-quality.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/checklists/06-review.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/checklists/07-commit.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/checklists/08-debug.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/checklists/09-optimize.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/checklists/10-document.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/checklists/index.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/code-quality.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/design/boundaries.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/design/concurrency.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/design/data-structures.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/design/errors.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/design/modules.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/ffi.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/index.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/language.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/libraries/arrow-parquet.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/libraries/gix.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/libraries/pyo3.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/libraries/regex-automata.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/libraries/roaring-fst.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/libraries/tantivy.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/libraries/zstd.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/naming.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/testing.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/docs/standards/rust/unsafe.md +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/rust-toolchain.toml +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/agentic_smoke.sh +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/bench/bench_concurrent_mixed.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/bench/bench_hosted_adversarial.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/bench/stress_mcp_multiprocess.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/grokmirror-personal.conf +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/grokmirror.conf +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/klmcp-doctor.sh +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/klmcp-grok-pull.sh +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/klmcp-ingest.sh +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/post-pull-hook.sh +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/rust_call_graph.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/systemd/etc-kernel-lore-mcp-env.sample +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/systemd/klmcp-grokmirror.service +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/systemd/klmcp-grokmirror.timer +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/systemd/klmcp-ingest.path +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/systemd/klmcp-ingest.service +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/systemd/klmcp-mcp.service +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/systemd/klmcp-sync.service +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/scripts/systemd/klmcp-sync.timer +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/bin/bench_blob_read.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/bin/bench_ingest_stages.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/bin/build_git_sidecar.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/bin/build_over.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/bin/doctor.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/bin/ingest.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/bin/reindex.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/bm25.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/embedding.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/git_sidecar.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/ingest.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/__main__.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/_surface_manifest.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/cli/__init__.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/cli/doctor.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/cli/embed.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/cli/ingest.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/cli/sync.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/config.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/cursor.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/embedding.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/errors.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/freshness.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/kwic.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/logging_.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/mapping.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/models.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/observability.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/prompts.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/reader_cache.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/resources/__init__.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/resources/blind_spots.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/resources/coverage_stats.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/resources/templates.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/routes/__init__.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/routes/metrics.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/sampling.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/server.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/time_bounds.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/__init__.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/activity.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/author_footprint.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/author_profile.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/corpus_stats.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/expand_citation.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/explain_patch.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/file_timeline.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/fix_status.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/maintainer_profile.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/message.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/nearest.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/patch.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/patch_diff.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/patch_search.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/path_mentions.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/primitives.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/sampling_tools.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/search.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/series.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/stable_backport.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/subsystem_churn.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/thread.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/kernel_lore_mcp/tools/thread_state.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/maintainers.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/metadata.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/over.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/parse.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/path_tier.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/schema.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/state.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/store.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/sync.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/tid.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/trailer_refs.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/src/trigram.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/__init__.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/bin_ingest.rs +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/__init__.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/conftest.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/fixtures/__init__.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_annotations.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_cost_hints.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_coverage_stats.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_cursor.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_embedding_e2e.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_errors.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_fix_status.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_freshness.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_fuzzy_search.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_http_transport.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_ingest_and_reader.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_kwic.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_logging_profile.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_mcp_adversarial.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_mcp_tools_e2e.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_observability.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_path_mentions.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_primitives_e2e.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_prompts.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_regex_hosted.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_resource_templates.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_response_format.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_sampling_tools.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_smoke.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_status_subcommand.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_stdio_subprocess.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_surface_manifest.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_sync_cli.py +0 -0
- {kernel_lore_mcp-0.3.2 → kernel_lore_mcp-0.3.3}/tests/python/test_thread_patch_explain.py +0 -0
|
@@ -114,6 +114,11 @@ struct PhaseHeartbeat {
|
|
|
114
114
|
handle: Option<std::thread::JoinHandle<()>>,
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
struct StageHeartbeat {
|
|
118
|
+
stop: std::sync::Arc<AtomicBool>,
|
|
119
|
+
handle: Option<std::thread::JoinHandle<()>>,
|
|
120
|
+
}
|
|
121
|
+
|
|
117
122
|
#[derive(Debug, Clone, Serialize)]
|
|
118
123
|
struct SyncStatusRecord {
|
|
119
124
|
version: String,
|
|
@@ -195,6 +200,23 @@ impl SyncStateReporter {
|
|
|
195
200
|
})
|
|
196
201
|
}
|
|
197
202
|
|
|
203
|
+
fn refresh_stage(
|
|
204
|
+
&self,
|
|
205
|
+
stage: &str,
|
|
206
|
+
note: Option<String>,
|
|
207
|
+
elapsed_secs: f64,
|
|
208
|
+
memory: MemorySnapshot,
|
|
209
|
+
) -> Result<()> {
|
|
210
|
+
self.update(|status| {
|
|
211
|
+
status.stage = stage.to_string();
|
|
212
|
+
status.note = note;
|
|
213
|
+
status.elapsed_secs = elapsed_secs;
|
|
214
|
+
status.process_rss_mb = memory.process_rss_bytes.map(bytes_to_mib);
|
|
215
|
+
status.memory_available_mb = memory.available_bytes.map(bytes_to_mib);
|
|
216
|
+
status.memory_total_mb = memory.total_bytes.map(bytes_to_mib);
|
|
217
|
+
})
|
|
218
|
+
}
|
|
219
|
+
|
|
198
220
|
fn set_phase_progress(
|
|
199
221
|
&self,
|
|
200
222
|
stage: &str,
|
|
@@ -331,6 +353,46 @@ impl Drop for PhaseHeartbeat {
|
|
|
331
353
|
}
|
|
332
354
|
}
|
|
333
355
|
|
|
356
|
+
impl Drop for StageHeartbeat {
|
|
357
|
+
fn drop(&mut self) {
|
|
358
|
+
self.stop.store(true, Ordering::Relaxed);
|
|
359
|
+
if let Some(handle) = self.handle.take() {
|
|
360
|
+
handle.thread().unpark();
|
|
361
|
+
let _ = handle.join();
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
fn stage_heartbeat(
|
|
367
|
+
sync_state: SyncStateReporter,
|
|
368
|
+
stage: &'static str,
|
|
369
|
+
note: Option<String>,
|
|
370
|
+
run_started: Instant,
|
|
371
|
+
) -> StageHeartbeat {
|
|
372
|
+
let stop = std::sync::Arc::new(AtomicBool::new(false));
|
|
373
|
+
let stop_for_thread = std::sync::Arc::clone(&stop);
|
|
374
|
+
let stage_name = stage.to_string();
|
|
375
|
+
let handle = std::thread::spawn(move || {
|
|
376
|
+
loop {
|
|
377
|
+
std::thread::park_timeout(PROGRESS_LOG_INTERVAL);
|
|
378
|
+
if stop_for_thread.load(Ordering::Relaxed) {
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
381
|
+
let elapsed_secs = run_started.elapsed().as_secs_f64();
|
|
382
|
+
let memory = current_memory_snapshot();
|
|
383
|
+
if let Err(e) =
|
|
384
|
+
sync_state.refresh_stage(&stage_name, note.clone(), elapsed_secs, memory)
|
|
385
|
+
{
|
|
386
|
+
tracing::warn!(stage = stage_name, error = %e, "failed to write sync status");
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
StageHeartbeat {
|
|
391
|
+
stop,
|
|
392
|
+
handle: Some(handle),
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
334
396
|
fn main() -> Result<()> {
|
|
335
397
|
tracing_subscriber::fmt()
|
|
336
398
|
.with_writer(std::io::stderr)
|
|
@@ -688,16 +750,15 @@ fn main() -> Result<()> {
|
|
|
688
750
|
if let Some(ref bm25_mutex) = bm25 {
|
|
689
751
|
let memory = current_memory_snapshot();
|
|
690
752
|
let config = bm25_config.expect("bm25 config must exist when writer exists");
|
|
753
|
+
let note = Some(format!(
|
|
754
|
+
"threads={} memory_budget_mb={}",
|
|
755
|
+
config.num_threads,
|
|
756
|
+
config.memory_budget_mb()
|
|
757
|
+
));
|
|
691
758
|
sync_state
|
|
692
|
-
.set_stage(
|
|
693
|
-
"bm25_commit",
|
|
694
|
-
Some(format!(
|
|
695
|
-
"threads={} memory_budget_mb={}",
|
|
696
|
-
config.num_threads,
|
|
697
|
-
config.memory_budget_mb()
|
|
698
|
-
)),
|
|
699
|
-
)
|
|
759
|
+
.set_stage("bm25_commit", note.clone())
|
|
700
760
|
.context("update sync status to bm25_commit")?;
|
|
761
|
+
let stage_guard = stage_heartbeat(sync_state.clone(), "bm25_commit", note, start);
|
|
701
762
|
tracing::info!(
|
|
702
763
|
bm25_writer_threads = config.num_threads,
|
|
703
764
|
bm25_memory_budget_mb = config.memory_budget_mb(),
|
|
@@ -718,6 +779,7 @@ fn main() -> Result<()> {
|
|
|
718
779
|
memory_total_mb = ?memory.total_bytes.map(bytes_to_mib),
|
|
719
780
|
"bm25 commit done"
|
|
720
781
|
);
|
|
782
|
+
drop(stage_guard);
|
|
721
783
|
}
|
|
722
784
|
|
|
723
785
|
// tid rebuild: reasonable to do every sync tick; touches only the
|
|
@@ -725,6 +787,7 @@ fn main() -> Result<()> {
|
|
|
725
787
|
sync_state
|
|
726
788
|
.set_stage("tid_rebuild", None)
|
|
727
789
|
.context("update sync status to tid_rebuild")?;
|
|
790
|
+
let tid_stage_guard = stage_heartbeat(sync_state.clone(), "tid_rebuild", None, start);
|
|
728
791
|
tracing::info!("tid rebuild starting");
|
|
729
792
|
let tid_result = _core::rebuild_tid(&data_dir).context("rebuild tid side-table")?;
|
|
730
793
|
tracing::info!(
|
|
@@ -732,9 +795,11 @@ fn main() -> Result<()> {
|
|
|
732
795
|
path = %tid_result.0.display(),
|
|
733
796
|
"tid rebuild done"
|
|
734
797
|
);
|
|
798
|
+
drop(tid_stage_guard);
|
|
735
799
|
sync_state
|
|
736
800
|
.set_stage("path_vocab_rebuild", None)
|
|
737
801
|
.context("update sync status to path_vocab_rebuild")?;
|
|
802
|
+
let path_stage_guard = stage_heartbeat(sync_state.clone(), "path_vocab_rebuild", None, start);
|
|
738
803
|
tracing::info!("path vocab rebuild starting");
|
|
739
804
|
if let Some(path_count) = rebuild_path_vocab_after_sync(&data_dir)? {
|
|
740
805
|
tracing::info!(
|
|
@@ -743,6 +808,7 @@ fn main() -> Result<()> {
|
|
|
743
808
|
"path vocab rebuild done"
|
|
744
809
|
);
|
|
745
810
|
}
|
|
811
|
+
drop(path_stage_guard);
|
|
746
812
|
|
|
747
813
|
// Tally.
|
|
748
814
|
let mut total_ingested: u64 = 0;
|
|
@@ -29,6 +29,14 @@ class TidRebuildResult(TypedDict):
|
|
|
29
29
|
path: str
|
|
30
30
|
rows: int
|
|
31
31
|
|
|
32
|
+
class _RequestCancelGuard:
|
|
33
|
+
def close(self) -> None: ...
|
|
34
|
+
|
|
35
|
+
class _RequestCancelToken:
|
|
36
|
+
def __init__(self) -> None: ...
|
|
37
|
+
def cancel(self) -> None: ...
|
|
38
|
+
def install(self) -> _RequestCancelGuard: ...
|
|
39
|
+
|
|
32
40
|
def rebuild_tid(data_dir: str | PathLike[str]) -> TidRebuildResult: ...
|
|
33
41
|
def rebuild_bm25(data_dir: str | PathLike[str]) -> int: ...
|
|
34
42
|
def backfill_subject_normalized(data_dir: str | PathLike[str]) -> int: ...
|
|
@@ -41,7 +41,7 @@ import structlog
|
|
|
41
41
|
|
|
42
42
|
from kernel_lore_mcp.config import get_settings
|
|
43
43
|
from kernel_lore_mcp.errors import LoreError
|
|
44
|
-
from kernel_lore_mcp.health import suggest_retry_after_seconds
|
|
44
|
+
from kernel_lore_mcp.health import should_shed_tool_call, suggest_retry_after_seconds
|
|
45
45
|
from kernel_lore_mcp.logging_ import profiling_thresholds
|
|
46
46
|
|
|
47
47
|
CostClass = Literal["cheap", "moderate", "expensive"]
|
|
@@ -147,6 +147,30 @@ def cost_limited(
|
|
|
147
147
|
# Pair with a zero-timeout acquire for the "reject fast"
|
|
148
148
|
# shape — acquire() would block if locked.
|
|
149
149
|
base_started = current_tool_request_started() or time.monotonic()
|
|
150
|
+
settings = get_settings()
|
|
151
|
+
should_shed, shed_reason = should_shed_tool_call(
|
|
152
|
+
data_dir=settings.data_dir,
|
|
153
|
+
cost_class=cost,
|
|
154
|
+
)
|
|
155
|
+
if should_shed:
|
|
156
|
+
queue_wait = max(0.0, time.monotonic() - base_started)
|
|
157
|
+
record_tool_queue_wait(
|
|
158
|
+
tool_name,
|
|
159
|
+
cost,
|
|
160
|
+
queue_wait,
|
|
161
|
+
"rate_limited",
|
|
162
|
+
)
|
|
163
|
+
log.warning(
|
|
164
|
+
"tool admission shed",
|
|
165
|
+
tool=tool_name,
|
|
166
|
+
cost_class=cost,
|
|
167
|
+
mode=settings.mode,
|
|
168
|
+
queue_wait_ms=round(queue_wait * 1000, 3),
|
|
169
|
+
inflight=current_inflight(cost),
|
|
170
|
+
limit=_LIMITS[cost],
|
|
171
|
+
reason=shed_reason,
|
|
172
|
+
)
|
|
173
|
+
raise _rate_limited(cost, tool_name)
|
|
150
174
|
try:
|
|
151
175
|
await asyncio.wait_for(sem.acquire(), timeout=0.001)
|
|
152
176
|
except TimeoutError as err:
|
|
@@ -157,7 +181,6 @@ def cost_limited(
|
|
|
157
181
|
queue_wait,
|
|
158
182
|
"rate_limited",
|
|
159
183
|
)
|
|
160
|
-
settings = get_settings()
|
|
161
184
|
log.warning(
|
|
162
185
|
"tool admission rejected",
|
|
163
186
|
tool=tool_name,
|
|
@@ -11,6 +11,14 @@ from pathlib import Path
|
|
|
11
11
|
from typing import Any
|
|
12
12
|
|
|
13
13
|
_ACTIVE_SYNC_STALE_AFTER_SECONDS = 30
|
|
14
|
+
_SYNC_SHED_STAGES = {
|
|
15
|
+
"ingest",
|
|
16
|
+
"bm25_commit",
|
|
17
|
+
"tid_rebuild",
|
|
18
|
+
"path_vocab_rebuild",
|
|
19
|
+
"generation_bump",
|
|
20
|
+
"save_manifest",
|
|
21
|
+
}
|
|
14
22
|
|
|
15
23
|
|
|
16
24
|
def writer_lock_present(data_dir: Path) -> bool:
|
|
@@ -62,9 +70,7 @@ def read_sync_state(data_dir: Path) -> dict[str, Any] | None:
|
|
|
62
70
|
active = bool(payload.get("active"))
|
|
63
71
|
if heartbeat_age_seconds is not None:
|
|
64
72
|
active = (
|
|
65
|
-
active
|
|
66
|
-
and writer_active
|
|
67
|
-
and heartbeat_age_seconds <= _ACTIVE_SYNC_STALE_AFTER_SECONDS
|
|
73
|
+
active and writer_active and heartbeat_age_seconds <= _ACTIVE_SYNC_STALE_AFTER_SECONDS
|
|
68
74
|
)
|
|
69
75
|
else:
|
|
70
76
|
active = active and writer_active
|
|
@@ -122,6 +128,26 @@ def suggest_retry_after_seconds(
|
|
|
122
128
|
return retry_after, None
|
|
123
129
|
|
|
124
130
|
|
|
131
|
+
def should_shed_tool_call(*, data_dir: Path, cost_class: str) -> tuple[bool, str | None]:
|
|
132
|
+
"""Whether the server should fast-reject this tool class.
|
|
133
|
+
|
|
134
|
+
Cheap indexed lookups stay available as long as the process is up.
|
|
135
|
+
Moderate and expensive tools shed aggressively while a writer-heavy
|
|
136
|
+
sync stage is active so a serving box does not spend its remaining
|
|
137
|
+
headroom on work we already expect to be slow or likely to timeout.
|
|
138
|
+
"""
|
|
139
|
+
if cost_class == "cheap":
|
|
140
|
+
return False, None
|
|
141
|
+
|
|
142
|
+
sync = read_sync_state(data_dir)
|
|
143
|
+
if sync and sync.get("active"):
|
|
144
|
+
stage = str(sync.get("stage") or "").strip()
|
|
145
|
+
if stage in _SYNC_SHED_STAGES:
|
|
146
|
+
return True, f"sync stage `{stage}` is reserving capacity"
|
|
147
|
+
|
|
148
|
+
return False, None
|
|
149
|
+
|
|
150
|
+
|
|
125
151
|
def _coerce_int(value: object) -> int | None:
|
|
126
152
|
if isinstance(value, bool):
|
|
127
153
|
return None
|
|
@@ -66,10 +66,9 @@ def _per_list_shards(data_dir: Path) -> dict[str, list[dict[str, str]]]:
|
|
|
66
66
|
return out
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
def _build_status(settings: Settings) -> dict[str, Any]:
|
|
69
|
+
def _build_status(settings: Settings, *, include_per_list: bool) -> dict[str, Any]:
|
|
70
70
|
data_dir = settings.data_dir
|
|
71
71
|
generation, last_ingest = _read_generation(data_dir)
|
|
72
|
-
per_list = _per_list_shards(data_dir)
|
|
73
72
|
writer_lock = writer_lock_present(data_dir)
|
|
74
73
|
sync = read_sync_state(data_dir)
|
|
75
74
|
|
|
@@ -85,7 +84,7 @@ def _build_status(settings: Settings) -> dict[str, Any]:
|
|
|
85
84
|
# that pairs with the Prometheus gauge.
|
|
86
85
|
freshness_ok = last_ingest_age_seconds < 3 * interval
|
|
87
86
|
|
|
88
|
-
|
|
87
|
+
body = {
|
|
89
88
|
"service": "kernel-lore-mcp",
|
|
90
89
|
"version": _native_version(),
|
|
91
90
|
"generation": generation,
|
|
@@ -96,10 +95,13 @@ def _build_status(settings: Settings) -> dict[str, Any]:
|
|
|
96
95
|
"writer_lock_present": writer_lock,
|
|
97
96
|
"sync_active": bool(sync and sync.get("active")),
|
|
98
97
|
"sync": sync,
|
|
99
|
-
"
|
|
98
|
+
"per_list_omitted": not include_per_list,
|
|
100
99
|
"capabilities": capabilities(data_dir),
|
|
101
100
|
"blind_spots_ref": "blind-spots://coverage",
|
|
102
101
|
}
|
|
102
|
+
if include_per_list:
|
|
103
|
+
body["per_list"] = _per_list_shards(data_dir)
|
|
104
|
+
return body
|
|
103
105
|
|
|
104
106
|
|
|
105
107
|
def capabilities(data_dir: Path) -> dict[str, bool]:
|
|
@@ -158,7 +160,11 @@ def _native_version() -> str:
|
|
|
158
160
|
return "unknown"
|
|
159
161
|
|
|
160
162
|
|
|
161
|
-
def get_status(
|
|
163
|
+
def get_status(
|
|
164
|
+
settings: Settings | None = None,
|
|
165
|
+
*,
|
|
166
|
+
include_per_list: bool = False,
|
|
167
|
+
) -> dict[str, Any]:
|
|
162
168
|
"""Cached status builder. Used by both the MCP route and tests.
|
|
163
169
|
|
|
164
170
|
Cache is keyed by `data_dir` so multiple in-process servers (or
|
|
@@ -169,7 +175,7 @@ def get_status(settings: Settings | None = None) -> dict[str, Any]:
|
|
|
169
175
|
from kernel_lore_mcp.config import get_settings
|
|
170
176
|
|
|
171
177
|
settings = get_settings()
|
|
172
|
-
cache_key =
|
|
178
|
+
cache_key = f"{settings.data_dir}|per_list={int(include_per_list)}"
|
|
173
179
|
ttl = settings.freshness_cache_ttl_seconds
|
|
174
180
|
now = time.monotonic()
|
|
175
181
|
live_writer = writer_lock_present(settings.data_dir)
|
|
@@ -178,7 +184,7 @@ def get_status(settings: Settings | None = None) -> dict[str, Any]:
|
|
|
178
184
|
cached_at, body = _cache[cache_key]
|
|
179
185
|
if now - cached_at < effective_ttl:
|
|
180
186
|
return body
|
|
181
|
-
body = _build_status(settings)
|
|
187
|
+
body = _build_status(settings, include_per_list=include_per_list)
|
|
182
188
|
_cache[cache_key] = (now, body)
|
|
183
189
|
return body
|
|
184
190
|
|
|
@@ -190,4 +196,6 @@ def clear_cache() -> None:
|
|
|
190
196
|
|
|
191
197
|
async def status_endpoint(request: Request) -> JSONResponse:
|
|
192
198
|
"""Starlette/FastMCP custom-route handler."""
|
|
193
|
-
|
|
199
|
+
raw = (request.query_params.get("per_list") or "").strip().lower()
|
|
200
|
+
include_per_list = raw in {"1", "true", "yes", "on"}
|
|
201
|
+
return JSONResponse(get_status(include_per_list=include_per_list))
|
|
@@ -24,6 +24,7 @@ from kernel_lore_mcp.config import get_settings
|
|
|
24
24
|
from kernel_lore_mcp.errors import LoreError
|
|
25
25
|
from kernel_lore_mcp.health import suggest_retry_after_seconds
|
|
26
26
|
from kernel_lore_mcp.logging_ import profiling_thresholds
|
|
27
|
+
from kernel_lore_mcp import _core
|
|
27
28
|
|
|
28
29
|
log = structlog.get_logger(__name__)
|
|
29
30
|
|
|
@@ -45,9 +46,18 @@ async def run_with_timeout[T](
|
|
|
45
46
|
ms = timeout_ms or settings.query_wall_clock_ms
|
|
46
47
|
tool_name = getattr(fn, "__name__", str(fn))
|
|
47
48
|
started = time.monotonic()
|
|
49
|
+
token = _core._RequestCancelToken()
|
|
50
|
+
|
|
51
|
+
def _invoke_with_cancel() -> T:
|
|
52
|
+
guard = token.install()
|
|
53
|
+
try:
|
|
54
|
+
return fn(*args)
|
|
55
|
+
finally:
|
|
56
|
+
guard.close()
|
|
57
|
+
|
|
48
58
|
try:
|
|
49
59
|
result = await asyncio.wait_for(
|
|
50
|
-
asyncio.to_thread(
|
|
60
|
+
asyncio.to_thread(_invoke_with_cancel),
|
|
51
61
|
timeout=ms / 1000.0,
|
|
52
62
|
)
|
|
53
63
|
elapsed = time.monotonic() - started
|
|
@@ -85,10 +95,24 @@ async def run_with_timeout[T](
|
|
|
85
95
|
echoed_input=echoed_input or {},
|
|
86
96
|
retry_after_seconds=retry_after_seconds,
|
|
87
97
|
) from None
|
|
98
|
+
except asyncio.CancelledError:
|
|
99
|
+
elapsed = time.monotonic() - started
|
|
100
|
+
record_tool_runtime(tool_name, elapsed, "cancelled")
|
|
101
|
+
log.warning(
|
|
102
|
+
"tool runtime cancelled",
|
|
103
|
+
operation=tool_name,
|
|
104
|
+
mode=settings.mode,
|
|
105
|
+
runtime_ms=round(elapsed * 1000, 3),
|
|
106
|
+
timeout_ms=ms,
|
|
107
|
+
)
|
|
108
|
+
raise
|
|
88
109
|
except LoreError as exc:
|
|
89
110
|
elapsed = time.monotonic() - started
|
|
90
111
|
record_tool_runtime(tool_name, elapsed, exc.code)
|
|
91
|
-
if
|
|
112
|
+
if (
|
|
113
|
+
exc.code != "query_timeout"
|
|
114
|
+
and elapsed >= profiling_thresholds(settings.mode).tool_seconds
|
|
115
|
+
):
|
|
92
116
|
log.info(
|
|
93
117
|
"tool runtime completed",
|
|
94
118
|
operation=tool_name,
|
|
@@ -109,6 +133,8 @@ async def run_with_timeout[T](
|
|
|
109
133
|
timeout_ms=ms,
|
|
110
134
|
)
|
|
111
135
|
raise
|
|
136
|
+
finally:
|
|
137
|
+
token.cancel()
|
|
112
138
|
|
|
113
139
|
|
|
114
140
|
__all__ = ["run_with_timeout"]
|
|
@@ -113,6 +113,8 @@ fn _core(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
|
113
113
|
m.add_function(wrap_pyfunction!(crate::python::py_embedding_meta, m)?)?;
|
|
114
114
|
m.add_class::<crate::python::PyReader>()?;
|
|
115
115
|
m.add_class::<crate::python::PyEmbeddingBuilder>()?;
|
|
116
|
+
m.add_class::<crate::python::PyRequestCancelToken>()?;
|
|
117
|
+
m.add_class::<crate::python::PyRequestCancelGuard>()?;
|
|
116
118
|
Ok(())
|
|
117
119
|
}
|
|
118
120
|
|
|
@@ -24,7 +24,53 @@ use crate::ingest;
|
|
|
24
24
|
use crate::reader::{DiffMode, EqField, MessageRow, Reader as CoreReader, RegexField};
|
|
25
25
|
use crate::router;
|
|
26
26
|
use crate::tid;
|
|
27
|
-
use crate::timeout::DeadlineGuard;
|
|
27
|
+
use crate::timeout::{CancelGuard, CancelToken, DeadlineGuard};
|
|
28
|
+
|
|
29
|
+
#[pyclass(
|
|
30
|
+
module = "kernel_lore_mcp._core",
|
|
31
|
+
name = "_RequestCancelToken",
|
|
32
|
+
skip_from_py_object
|
|
33
|
+
)]
|
|
34
|
+
#[derive(Clone)]
|
|
35
|
+
pub struct PyRequestCancelToken {
|
|
36
|
+
inner: CancelToken,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
#[pymethods]
|
|
40
|
+
impl PyRequestCancelToken {
|
|
41
|
+
#[new]
|
|
42
|
+
fn new() -> Self {
|
|
43
|
+
Self {
|
|
44
|
+
inner: CancelToken::new(),
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fn cancel(&self) {
|
|
49
|
+
self.inner.cancel();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fn install(&self) -> PyRequestCancelGuard {
|
|
53
|
+
PyRequestCancelGuard {
|
|
54
|
+
guard: Some(CancelGuard::install(self.inner.clone())),
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
#[pyclass(
|
|
60
|
+
module = "kernel_lore_mcp._core",
|
|
61
|
+
name = "_RequestCancelGuard",
|
|
62
|
+
skip_from_py_object
|
|
63
|
+
)]
|
|
64
|
+
pub struct PyRequestCancelGuard {
|
|
65
|
+
guard: Option<CancelGuard>,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
#[pymethods]
|
|
69
|
+
impl PyRequestCancelGuard {
|
|
70
|
+
fn close(&mut self) {
|
|
71
|
+
self.guard.take();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
28
74
|
|
|
29
75
|
/// Install a thread-local deadline for the duration of one reader
|
|
30
76
|
/// query, matching the router-layer wall-clock cap. Cheap — ~one
|
|
@@ -2571,6 +2571,7 @@ fn parallel_confirm_substring(
|
|
|
2571
2571
|
|
|
2572
2572
|
const CHUNK: usize = 256;
|
|
2573
2573
|
let deadline = crate::timeout::current_deadline();
|
|
2574
|
+
let cancel = crate::timeout::current_cancel_token();
|
|
2574
2575
|
let mut confirmed: Vec<MessageRow> = Vec::with_capacity(limit);
|
|
2575
2576
|
for chunk in date_sorted_hits.chunks(CHUNK) {
|
|
2576
2577
|
crate::timeout::check_request_deadline()?;
|
|
@@ -2584,6 +2585,7 @@ fn parallel_confirm_substring(
|
|
|
2584
2585
|
.par_iter()
|
|
2585
2586
|
.map(|row| -> Result<Option<MessageRow>> {
|
|
2586
2587
|
let _g = deadline.map(crate::timeout::DeadlineGuard::install);
|
|
2588
|
+
let _c = cancel.clone().map(crate::timeout::CancelGuard::install);
|
|
2587
2589
|
crate::timeout::check_request_deadline()?;
|
|
2588
2590
|
let store = reader.store_for(&row.list)?;
|
|
2589
2591
|
let body = store.read_at(row.body_segment_id, row.body_offset)?;
|
|
@@ -2653,9 +2655,11 @@ fn collect_trigram_candidates(
|
|
|
2653
2655
|
Mutex::new(std::collections::HashSet::new());
|
|
2654
2656
|
let overflowed = AtomicBool::new(false);
|
|
2655
2657
|
let deadline = crate::timeout::current_deadline();
|
|
2658
|
+
let cancel = crate::timeout::current_cancel_token();
|
|
2656
2659
|
|
|
2657
2660
|
all_segs.par_iter().try_for_each(|seg_dir| -> Result<()> {
|
|
2658
2661
|
let _g = deadline.map(crate::timeout::DeadlineGuard::install);
|
|
2662
|
+
let _c = cancel.clone().map(crate::timeout::CancelGuard::install);
|
|
2659
2663
|
crate::timeout::check_request_deadline()?;
|
|
2660
2664
|
if overflowed.load(Ordering::Relaxed) {
|
|
2661
2665
|
return Ok(());
|
|
@@ -2710,6 +2714,7 @@ fn parallel_confirm_fuzzy(
|
|
|
2710
2714
|
|
|
2711
2715
|
const CHUNK: usize = 256;
|
|
2712
2716
|
let deadline = crate::timeout::current_deadline();
|
|
2717
|
+
let cancel = crate::timeout::current_cancel_token();
|
|
2713
2718
|
let mut confirmed: Vec<MessageRow> = Vec::with_capacity(limit);
|
|
2714
2719
|
for chunk in date_sorted_hits.chunks(CHUNK) {
|
|
2715
2720
|
crate::timeout::check_request_deadline()?;
|
|
@@ -2720,6 +2725,7 @@ fn parallel_confirm_fuzzy(
|
|
|
2720
2725
|
.par_iter()
|
|
2721
2726
|
.map(|row| -> Result<Option<MessageRow>> {
|
|
2722
2727
|
let _g = deadline.map(crate::timeout::DeadlineGuard::install);
|
|
2728
|
+
let _c = cancel.clone().map(crate::timeout::CancelGuard::install);
|
|
2723
2729
|
crate::timeout::check_request_deadline()?;
|
|
2724
2730
|
let store = reader.store_for(&row.list)?;
|
|
2725
2731
|
let body = store.read_at(row.body_segment_id, row.body_offset)?;
|
|
@@ -398,20 +398,24 @@ pub fn dispatch(
|
|
|
398
398
|
// DeadlineGuard::install so scan() checks within the tier honor
|
|
399
399
|
// the same budget.
|
|
400
400
|
let deadline = crate::timeout::current_deadline();
|
|
401
|
+
let cancel = crate::timeout::current_cancel_token();
|
|
401
402
|
let mut meta_out: TierOut = Ok((None, None));
|
|
402
403
|
let mut trigram_out: TierOut = Ok((None, None));
|
|
403
404
|
let mut bm25_out: TierOut = Ok((None, None));
|
|
404
405
|
rayon::scope(|s| {
|
|
405
406
|
s.spawn(|_| {
|
|
406
407
|
let _g = deadline.map(crate::timeout::DeadlineGuard::install);
|
|
408
|
+
let _c = cancel.clone().map(crate::timeout::CancelGuard::install);
|
|
407
409
|
meta_out = run_metadata();
|
|
408
410
|
});
|
|
409
411
|
s.spawn(|_| {
|
|
410
412
|
let _g = deadline.map(crate::timeout::DeadlineGuard::install);
|
|
413
|
+
let _c = cancel.clone().map(crate::timeout::CancelGuard::install);
|
|
411
414
|
trigram_out = run_trigram();
|
|
412
415
|
});
|
|
413
416
|
s.spawn(|_| {
|
|
414
417
|
let _g = deadline.map(crate::timeout::DeadlineGuard::install);
|
|
418
|
+
let _c = cancel.clone().map(crate::timeout::CancelGuard::install);
|
|
415
419
|
bm25_out = run_bm25();
|
|
416
420
|
});
|
|
417
421
|
});
|