Repository navigation
Comparing changes
Open a pull request
base repository: cdeust/Cortex
base: v4.23.4
head repository: cdeust/Cortex
compare: v4.23.5
- 5 commits
- 63 files changed
- 2 contributors
Commits on Sep 23, 2026
-
fix(setup): persist backend marker before setup.py can fail; close ML…
…-child isolation gap (#638) * fix(setup): persist backend marker before setup.py can fail; close ML-child isolation gap Two Windows-reported defects (issue #633), both cross-platform in the underlying pin lists / code paths even though only observed there: 1. install-plugin.sh wrote ~/.claude/methodology/backend.json only after running scripts/setup.py, guarded by `|| fail`. Any setup failure discarded the already-correct Phase 0 backend decision. On the next launch, memory_config._detect_runtime() defaults to "cli" (the plugin's own CORTEX_RUNTIME="" resolves there), and memory_store._construct_store() forces backend="postgresql" whenever runtime=="cli" and backend=="auto", so a missing marker silently converted a chosen SQLite install into a hard PostgreSQL requirement, with none ever provisioned. Fixed: the marker now persists immediately after the backend is decided, before setup can fail and exit. 2. scripts/setup.py's cache_embedding_model() and its macOS/Linux twin scripts/lib/precache_embedding_model.sh spawn a child process that reaches deps/ only through PYTHONPATH, which cannot cut user site-packages the way launcher_site.isolate_deps() does in-process (issue #621), so a conflicting user-site torch/torchaudio build could still abort the embedding-model pre-cache. Both now bootstrap isolate_deps() in the child before importing sentence_transformers. scripts/setup.py's cache_embedding_model payload is pulled into a standalone, unit-tested _model_cache_child_source() function. _model_checks() also widens ImportError to Exception, matching _postgres_checks()'s own pattern, so a torch ABI mismatch (OSError or RuntimeError) reports a [FAIL] row instead of crashing verify() outright, closing the "exited before reporting any check" failure mode. setup_database() needed no such bootstrap (its child imports only psycopg and pg_schema, not the ML stack); audited and documented rather than assumed. Decisions recorded as ADR-1087 and ADR-1088 (wiki/adr/), per the decision-gate: large rationale blocks belong in the wiki, code keeps a short `# source: ADR-NNNN` pointer. New regression test (test_install_plugin_marker_order.py) drives the real installer against a python3 stub that fails only scripts/setup.py, proving the marker survives, verified to fail on the pre-fix script and pass on the fixed one. New tests compile and run _model_cache_child_source() end-to-end against a stubbed sentence_transformers, and prove repr() escapes Windows-shaped paths (backslashes, an apostrophe) correctly. Full suite: 9117 passed, 11 skipped (darwin). Windows unverified in this environment; CI's ci-sqlite-min.txt job is the nearest proxy. Known: this branch's ADR-1087/1088 and the sibling issue #634 fix branch's ADR-1087 were assigned independently from the same tip and collide on number 1087 with different content. Whichever PR merges second must renumber (file, wiki/manifest.json entry, mirror under docs/adr/, and the `source: ADR-1087` pointers in this branch's scripts/setup.py and scripts/lib/precache_embedding_model.sh). Co-Authored-By: Claude Sonnet 5 <[email protected]> * test(scripts): dedupe the marker-order test's installer-drive boilerplate Caught by this branch's own craftsmanship gate once a real CI run finally ran on it: test_marker_persists_backend_on_a_successful_sqlite_install exceeded the 40-line method cap, duplicating the stub-writing and env-building steps already in the sibling failure-path test almost verbatim. Extracted _write_setup_py_stub(bin_dir, exit_code=...) (the prior failure-only stub, now parametrized on the stubbed exit code) and _run_installer(tmp_path, setup_py_exit_code=...) (the shared home/PATH-isolated subprocess.run call), plus a small _marker_backend() reader both tests' final assertions were duplicating too. Both tests now read as their actual distinguishing behavior (exit code in, marker survives or not) instead of repeating the installer-driving mechanics. No behavior change: both tests still pass unchanged. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MyRfKj1vpBm2yx3sXCN8ik * fix(tests): sandbox pip/pip3 in the installer marker-order test install-plugin.sh's stale-install pruning (phase 2b) runs pip3 show/ uninstall unconditionally against whatever pip3 resolves to on PATH. This test only stubbed python3, so in CI pip3 resolved to the real interpreter's pip and genuinely uninstalled this repo's own just-installed editable hypermnesia-mcp package, breaking the "Verify hook-free MCP host contract" step later in the same job (FileNotFoundError: hypermnesia-mcp). Reproduced deterministically via a CI rerun of PR #638 (same two jobs failed identically both times). Stub pip/pip3 as always-report-not-installed, matching the existing python3 stub pattern, so the pruning phase's uninstall branch is never reached. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MyRfKj1vpBm2yx3sXCN8ik * fix(installer): restore prior backend marker when a switch fails Review (PR #638) caught a real regression: persisting the marker before setup runs (this PR's own #633 fix) unconditionally overwrote a previously-persisted, working backend choice with the newly requested one before that new backend was ever confirmed working. A user switching from a working sqlite install to --postgres, whose postgres setup then fails, ended up with the marker pointing at postgresql with nothing provisioned -- issue #633's exact bug class, in reverse. Capture the marker's previous backend before overwriting it, and restore it whenever the newly requested backend differs and its setup fails. A fresh install (no prior marker) or a same-backend reinstall have nothing to restore, so #633's original scenario is untouched. Added a regression test that seeds a working sqlite marker, requests a postgres switch through the Windows branch (uname stubbed, which reuses the same stubbable scripts/setup.py path already used for the sqlite case), fails setup, and asserts the marker still reads sqlite. Also fixed: scripts/lib/precache_embedding_model.sh interpolated project_dir/deps_dir directly into single-quoted Python string literals, unlike its Python twin (_model_cache_child_source), which escapes via repr() per ADR-1087. A path containing a single quote or backslash would break the embedded Python source. Pass both paths through env vars instead, which need no escaping at all. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MyRfKj1vpBm2yx3sXCN8ik --------- Co-authored-by: Claude Sonnet 5 <[email protected]>
Configuration menu - View commit details
-
Copy full SHA for 85200ff - Browse repository at this point
Copy the full SHA 85200ffView commit details -
fix(consolidate): gate PG-only wiki passes once at wiring, not per ca…
…ll (#639) * fix(consolidate): turn silent PG-only crashes into named skips on SQLite Windows-reported (issue #636), but the root cause is not platform-specific: consolidate's wiki maintenance cycle runs four passes on every invocation (wiki_source_backfill_pass, wiki_domain_backfill_pass, wiki_citation_seed_pass, wiki_backlog_pass's lesson-promotion count), each needing store.batch_pool (a psycopg_pool.ConnectionPool only PgMemoryStore provides, since the SQL is Postgres-schema-qualified: wiki.pages, wiki.citations, %s placeholders). SqliteMemoryStore has no batch_pool attribute at all, so every one of these passes raised AttributeError on every SQLite install, on every run. Three of the four caught that AttributeError internally and returned {"status": "error: ..."} instead of letting it propagate. wiki_maintenance.py's own escalation only fired on a RAISE past the await, never on a returned error stanza, so consolidate kept reporting status: "ok" and failed_stages: [] while four maintenance passes were silently broken on the default backend, on every run. The fourth pass already degraded to None on the same AttributeError but mischaracterized SQLite as "fallback in tests", and called silent_failure.note() on every occurrence, incrementing cortex_silent_failures_total on every consolidate run for the lifetime of a SQLite install for a gap that isn't actually a failure. Fixed: - Added mcp_server/handlers/consolidation/batch_pool_capability.py, a shared batch_pool_skip_reason(store) guard. Every batch_pool-gated pass now checks it before entering its try block and returns {"status": "skipped: store has no batch_pool (non-PostgreSQL backend)"} instead of ever reaching AttributeError. Applied to the three consolidate-wired wiki passes and, since audit confirmed the identical unconditional store.batch_pool pattern, to the five standalone-campaign passes the issue flagged as unverified suspects (memory_dedup_exact_pass, memory_domain_backfill_pass, memory_reheat_pass, near_dup_calibration_pass's two entry points, write_class_backfill_pass). - wiki_maintenance.py gained _escalate_if_error(): it now also escalates out["status"] when a sub-pass RETURNS (not just raises) an "error:" status, fixing the previously dead escalation path. A "skipped: ..." status does not escalate. - wiki_backlog_pass._lesson_promotion_backlog checks the same guard first and returns None without calling silent_failure.note() when the capability is simply absent, reserving that call for a genuine query failure once batch_pool exists. Docstring no longer calls SQLite a test-only fallback. Decision recorded as ADR-1089 (wiki/adr/), per the decision-gate. Not 1087: two sibling branches from this same reporting session (fix/issue-634-sqlite-vec, fix/issue-633-backend-marker; PRs #637, #638) already claimed 1087 and 1088 independently from the same main tip, and both document that collision against each other. 1089 avoids adding a third branch to it; whichever PR merges last still renumbers as needed. Left out of scope, flagged for a separate decision: ingest_codebase.py's entity/edge ingestion also references store.batch_pool unconditionally, with no try/except at all, but its sink SQL uses PostgreSQL's COPY ... FROM STDIN wire protocol (mcp_server/infrastructure/staging_resolve_sink.py), which has no SQLite equivalent. This is a materially larger, pre-existing, PG-only architectural gap (crashes loudly today, not silently), not a simple missing-guard bug. New tests: unit coverage for the guard helper; a contract test running all nine fixed passes against a real, fresh SqliteMemoryStore built through the composition root, asserting every one degrades to "skipped: ..." and never "error: ..."; wiki_maintenance tests proving a returned (non-raised) error stanza now escalates, and that a skipped stanza does not. Full suite: 9157 passed, 11 skipped (darwin). Windows unverified in this environment. Co-Authored-By: Claude Sonnet 5 <[email protected]> * fix(consolidate): gate PG-only wiki passes once at wiring, not per call Reworks the previous commit (efac006) on this branch. That commit fixed issue #636's reported symptom (consolidate reports status ok while four wiki passes silently fail on SQLite) by adding a hasattr(store, "batch_pool") guard inside each of nine call sites, turning the AttributeError into a returned {"status": "skipped: ..."} stanza. Reviewed and rejected: that is a catch-and-degrade shim restating the same defect with a softer word, not a fix at the root, and the repo's own non-negotiable already says so ("no silent fallbacks or compatibility shims"). This commit fixes the actual root cause instead: wiki_maintenance.py wired four PostgreSQL-only passes (wiki_source_backfill_pass, wiki_domain_backfill_pass, wiki_citation_seed_pass, wiki_backlog_pass's lesson-promotion count) unconditionally, regardless of backend. run_wiki_maintenance now decides once, at the top, whether store is PostgreSQL-backed (hasattr(store, "batch_pool"), the same idiom this file already used for iter_memories_for_decay) and only invokes those four inside that branch. On SQLite they are simply absent from the response, the same way "wiki" itself is absent from consolidate's stats when wiki=False -- not reported as failed, not reported as skipped. The four passes no longer catch their own AttributeError (or any exception) for a missing-capability case: run_wiki_maintenance is each one's sole caller now, so being invoked without batch_pool is a wiring bug and raises, like any other broken precondition. This also revives wiki_maintenance's existing except blocks around each await as their real, only error boundary -- previously dead code, since every pass swallowed its own exception before the caller ever saw it. wiki_backlog_pass._lesson_promotion_backlog moves out of run_backlog_pass (unconditional, filesystem-based) into run_wiki_maintenance's own PostgreSQL branch; its try/except and silent_failure.note for a genuine query failure are unchanged (ADR-0640's accepted pattern), only the call site moved, which is what stops the metric from incrementing on every SQLite consolidate run. The five standalone campaign scripts sharing the identical store.batch_pool pattern (memory_dedup_exact_pass, memory_domain_backfill_pass, memory_reheat_pass, near_dup_calibration_pass's two entry points, write_class_backfill_pass) are not wired into consolidate and keep their original, pre-#636 try/except (a human runs the matching scripts/*.py CLI directly and reads the printed status) unchanged. Each script's entry point now checks hasattr(store, "batch_pool") once, before calling its pass, and exits 1 with a one-line message when absent. Deleted batch_pool_capability.py and its unit test (the shim and its own test); deleted test_wiki_batch_pool_sqlite_contract.py (tested the shim's "skipped:" status shape, no longer applicable). New tests in test_wiki_maintenance.py: the four PG-only keys are absent on a store without batch_pool and present on one with it; a contract test runs the whole cycle against a real, fresh SqliteMemoryStore built through the composition root and asserts no stanza anywhere has an "error:" status and the four keys are absent -- issue #636's own requested check. consolidate's tool schema documents the four keys as PostgreSQL-only. ADR renumbered 1089 -> 1090 (this branch's own number; the sibling PRs #637/#638 already claim 1087/1088) and rewritten to describe this design, including why the first (shim) version was rejected on review. Left out of scope, flagged separately: ingest_codebase.py's entity/edge ingestion also references store.batch_pool unconditionally, but its sink SQL uses PostgreSQL's COPY ... FROM STDIN wire protocol with no SQLite equivalent -- a materially larger, pre-existing, architectural gap, not a missing-guard bug. Full suite: 9146 passed, 11 skipped (darwin, same pre-existing 11 as before this branch). ruff check/format and the craftsmanship gate both clean. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MyRfKj1vpBm2yx3sXCN8ik * fix(consolidate): escalate lesson_promotion_backlog failures like the others Advisor review of the previous commit (f9398f1) on this branch found one remaining inconsistency: _lesson_promotion_backlog kept its own internal try/except, so a genuine PostgreSQL query failure (pool exhausted, table missing) degraded to lesson_promotion_backlog: None while out["status"] stayed "ok" -- the exact shape issue #636 reported, just for one key instead of four, and the one PG-only pass this branch's rework had not yet made consistent with the other three. Removed the try/except from _lesson_promotion_backlog: it now raises on a query failure like source_backfill/domain_backfill/citation_seed do. run_wiki_maintenance wraps the call in its own try/except and escalates out["status"] to "lesson_promotion_backlog_error: ..." on failure, matching the other three exactly. This also drops the silent_failure.note call the function no longer needs -- the wiring fix from the previous commit already means it is never invoked at all on a non-PostgreSQL store, which is what actually stops the metric pollution, not a swallowed exception. Regenerated .craftsmanship-baseline.json: removing wiki_backlog_pass.py's now-unused `mcp_server.observability` import fixed a pre-existing layer-violation baseline entry, which needed pruning as stale. New tests: wiki_backlog_pass's own unit tests now assert raise instead of a degraded None; a new wiki_maintenance test proves a real failure there escalates status exactly like the citation-seed equivalent. Full suite: 9147 passed, 11 skipped (darwin, same pre-existing 11). ruff and the craftsmanship gate both clean. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MyRfKj1vpBm2yx3sXCN8ik * fix(tests): build the contract test's store through the real composition root Review (PR #639) caught the contract test (TestRealSqliteStoreContract, issue #636's own requested check) instantiating SqliteMemoryStore(path) directly, bypassing get_shared_store/MemoryStore/_construct_store -- exactly the backend-selection logic this bug is about. Rebuilt it to force CORTEX_MEMORY_STORE_BACKEND=sqlite and go through get_shared_store(), clearing the memory-settings cache and shared-store singleton before and after, matching the pattern already used in tests_py/hooks/test_entry_backend_parity.py. Also fixed the non-blocking duplication finding: the five campaign scripts (memory_dedup_exact, memory_domain_backfill, memory_reheat, near_dup_calibrate, backfill_write_class) each carried an identical 7-line batch_pool guard. Extracted to mcp_server/shared/campaign_store_guard.py::require_postgres_store, behavior-preserving. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MyRfKj1vpBm2yx3sXCN8ik --------- Co-authored-by: Claude Sonnet 5 <[email protected]>
Configuration menu - View commit details
-
Copy full SHA for 4ee2f7b - Browse repository at this point
Copy the full SHA 4ee2f7bView commit details -
fix(sqlite): install sqlite-vec on every backend, self-heal vectorles…
…s rows (#637) * fix(sqlite): install sqlite-vec on every backend, self-heal vectorless rows Windows-reported (issue #634), but the root cause is not platform-specific: neither dependency-install path the plugin uses ever named the [sqlite] extra. - scripts/launcher_pins.py::BASE_PACKAGES (installed by ensure_deps() on every hook/session-start launch) listed the PostgreSQL drivers unconditionally but nothing from [sqlite]. - requirements/setup.txt, generated for extras (postgresql, codebase, benchmarks), is what scripts/setup.py::install_deps() installs on BOTH backends (SKIP_POSTGRES does not change which file is read). Consequence: the SQLite backend, the zero-config default, ran with vector search silently disabled (FTS-only) on every install, on every OS, while check_setup/doctor reported the store fully ready. Fixed: - Added "sqlite" to setup.txt's generated extras and sqlite-vec==0.1.9 to BASE_PACKAGES, pinned to match. Existing installs self-heal on next launch (ensure_deps()'s pin-satisfaction check compares sorted(pins), so the stamp mismatches and only the missing package installs). - SqliteMemoryStore.select_fallback_embeddings()'s re-embed worklist now also matches rows with a non-empty embedding_model but no memories_vec row (a vector computed but never persisted because sqlite-vec was absent at write time), so such rows self-heal once the extension becomes available. Previously only the embedding_model='fallback' label was matched, and a correctly-labelled 'neural' row with no vector could never resurface. - doctor/check_setup gained an optional _sqlite_vector_search check that distinguishes "package not installed" from "installed but this Python's sqlite3 cannot load extensions" (different fixes: reinstall vs. a different Python build). - The embedding_upgrade consolidation cycle's result now also carries vectors_persisted: 0 and a reason when the store cannot persist vectors at all, so "upgraded: N" is never misread as "N vectors written". Decision recorded as ADR-1087 (wiki/adr/), per the decision-gate: large rationale blocks belong in the wiki, code keeps a short `# source: ADR-NNNN` pointer. New tests cover the worklist's vector-gap backfill and its exclusion of never-embedded rows, the embedding_upgrade counter's vectors_persisted flag, and the doctor check's optional status and package-vs-extension distinction. select_fallback_embeddings benchmarked at 3.1 ms/call on a 10k-row in-memory store with 200 vectorless rows seeded (100 returned per call, the existing limit). Full suite: 9119 passed, 11 skipped (darwin). Windows unverified in this environment; CI's ci-sqlite-min.txt job is the nearest proxy. Known: this branch's ADR-1087 and the sibling issue #633 fix branch's ADR-1087/1088 were assigned independently from the same tip and collide on number 1087 with different content. Whichever PR merges second must renumber (file, wiki/manifest.json entry, mirror under docs/adr/, and the `source: ADR-1087` pointers in this branch's scripts/launcher_pins.py and scripts/pip_constraint_sets.py). Co-Authored-By: Claude Sonnet 5 <[email protected]> * fix(sqlite): stamp 'neural' only after the vector actually lands Reviewed and reworked. The root cause the previous commit on this branch (715f580) never touched: SqliteMemoryStore._insert_memory_rows, reembed_memory, and update_memory_compression each stamp memories.embedding_model unconditionally whenever an embedding is present, whether or not the vec INSERT for it actually succeeds. _stamp_embedding_model's own docstring already stated the precondition every caller violated ("memory_id refers to a just-written vec row"). A memory written while sqlite-vec is unavailable -- the exact population issue #634 describes -- gets stamped 'neural' with no row in memories_vec behind it. The tag has two readings tangled into one write path. 'fallback' records which encoder ran; the re-embed worklist keys on it (WHERE embedding_model = 'fallback'), and a fallback memory with no vector must still surface for upgrade, so it stamps unconditionally -- issue #169's own tested contract (test_embedding_model_stamped_fallback) requires exactly this and is unchanged. 'neural' is read elsewhere (sqlite_store_search.py's mixed-store cross-rank filter) as a claim that a neural vector exists; stamping it with no vector behind it is issue #634's bug, in one word: 'neural' stamped without a vector. _insert_memory_rows and update_memory_compression now resolve the model name and whether the vec write actually succeeded, then stamp when model != "neural" or persisted: 'fallback' always stamps, 'neural' stamps only when memories_vec genuinely received the row. reembed_memory needed no such split -- its only caller, run_embedding_upgrade_cycle, now checks store.has_vec once before calling it at all, so a persisted vector is already guaranteed by the time it runs. run_embedding_upgrade_cycle gains has_vec on the _FallbackWorklistStore Protocol and returns {"upgraded": 0, "reason": ...} before encoding or restamping anything when has_vec is false, touching nothing -- the correct behavior for a cycle that cannot persist what it would compute, not a reason to restamp and report the gap after the fact. The vectors_persisted field the previous commit added to paper over that restamping is deleted; there is nothing left for it to report. select_fallback_embeddings's widened worklist query (the NOT IN memories_vec sweep) is kept: once the stamp fix lands, no production write path can produce a 'neural'-without-vector row going forward, so the sweep's remaining job is a one-time migration, self-healing installs whose database already carries rows the pre-fix bug wrote (the reporter's own measured 86 such rows). _sqlite_vector_search (mcp_server/doctor.py) changes from optional=True to optional=False: sqlite-vec now ships in every install's base package set, so its absence or a load failure is a broken install, not a supported degraded mode. Craftsmanship gate follow-up: this branch's first commit pushed mcp_server/doctor.py, embedding_upgrade.py, and tests_py/test_doctor.py over the method-size and file-size caps with inline rationale that belonged in the wiki ADR, not the code -- caught by this branch's own CI run once triggered. Docstrings trimmed to short pointers; the sqlite-vec-specific tests move to a new tests_py/test_doctor_sqlite_vector_search.py to keep test_doctor.py under 300 lines. tests_py/invariants/test_I2_canonical_writer.py's ALLOWED_WRITERS line numbers for sqlite_store.py shifted by +3 from this diff; updated to match (same three writers, confirmed by reading each site, not assumed). ADR renumbered 1087 -> 1089 (this branch's own number; sibling PRs #638 and #639 already claim 1088/1090) and rewritten around the actual defect ('neural' stamped without its vector) instead of only the install-list gap; the wiki ADR is now this fix's single source of truth for the 'fallback' vs 'neural' semantics, referenced by every call site that must not re-collapse them. Left unaddressed, flagged for the maintainer: _try_load_vec logs INFO and sets has_vec=False when the extension fails to load. Hardening it to raise at store-open time would change startup behavior on interpreters without loadable-extension support (common on macOS system/Framework Python) -- a product decision, not bundled here. Full suite: 9121 passed, 11 skipped (darwin, same pre-existing 11). ruff and the craftsmanship gate both clean. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MyRfKj1vpBm2yx3sXCN8ik * fix(consolidation): declare has_vec as a property on _FallbackWorklistStore A bare has_vec: bool attribute annotation on the Protocol made pyright flag SqliteMemoryStore as unsafely overlapping the protocol (its own has_vec is a real @Property, not a data attribute), caught only once CI ran pull_request-triggered checks on this branch for the first time. Declaring has_vec as a Protocol @Property matches the real implementation and resolves the structural-overlap false positive. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MyRfKj1vpBm2yx3sXCN8ik * fix(sqlite): downgrade to 'fallback' instead of skipping the stamp Review (PR #637) caught a real regression, worse than the bug this branch fixes: the gate `model != "neural" or persisted` skipped _stamp_embedding_model entirely when a neural encode had no persisted vector. The row's embedding_model stayed at the schema default '', which select_fallback_embeddings's own WHERE clause excludes -- the row became permanently invisible to the re-embed worklist, unlike the pre-fix bug (a plain 'neural' mislabel) that this same PR's vec-gap self-heal sweep already catches. Every insert/compression-update now always stamps something: a neural encode with no persisted vector downgrades to 'fallback' (recoverable, matches issue #169's unconditional-fallback contract); every other case stamps its own resolved model name. Updated the test that asserted the orphaned '' state as correct to assert the downgrade and that the row surfaces in the worklist instead. ADR-1089 and its docs mirror updated to describe the actual final behavior. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MyRfKj1vpBm2yx3sXCN8ik * fix(tests): skip the neural-exclusion worklist test without sqlite-vec CI caught this on all four Test (Python 3.1x) matrix jobs, which don't install sqlite-vec (unlike the SQLite-backend job, which does): test_select_fallback_embeddings_worklist asserted a 'neural'-tagged insert is excluded from the fallback worklist, without has_vec being true. That assumption only ever held by accident, on the pre-fix code: a neural encode with no persisted vector used to be left unstamped (''), which is invisible to the worklist query for a different reason (the orphan bug this branch's own review just fixed). With the vector never actually able to persist, this test's "neural one" now correctly downgrades to 'fallback' and belongs in the worklist -- exactly test_neural_stamp_downgrades_to_fallback_without_a_persisted_vector's contract, already covered elsewhere in this file. Marked @_needs_vec, matching the file's existing convention for assertions that are only meaningful when sqlite-vec is actually available. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MyRfKj1vpBm2yx3sXCN8ik --------- Co-authored-by: Claude Sonnet 5 <[email protected]>
Configuration menu - View commit details
-
Copy full SHA for 9dbfe26 - Browse repository at this point
Copy the full SHA 9dbfe26View commit details -
ci(windows): target the Windows leg at what actually broke on Windows (…
…#640) * ci(windows): target the Windows leg at what actually broke on Windows Three issues this reporting session (#633, #634, #636) were all filed by a Windows end user and all slipped past ci.yml. A test-windows job already exists (runs-on: windows-latest, added alongside issue #621's fix): it runs a curated, hand-grown list of eight test files plus a real bash scripts/install-plugin.sh exercise of the install path. The list grew reactively, one file per Windows bug fixed, and never included tests_py/handlers/consolidation/, where issue #636 lived -- so nothing #636 touched has ever run on Windows in CI. A separate real gap: the job installs dependencies via pip install -r requirements/ci-sqlite-min.txt, a hash-pinned shortcut that always carries the [sqlite] extra. The real install path (install-plugin.sh -> scripts/setup.py -> ensure_deps() reading launcher_pins.py::BASE_PACKAGES) never named sqlite-vec there -- issue #634's exact root cause. The job already runs that real path via install-plugin.sh, but nothing checked its output, so the one dependency gap Windows CI could have caught directly went unchecked regardless. Two additive changes, nothing else in the job's shape or budget touched: Added the four existing test files issues #634 and #636 actually changed to the curated list, following the exact convention already in place ("the new file joins the Windows CI leg beside its sibling"): tests_py/infrastructure/test_semantic_fallback_169.py and tests_py/test_doctor.py (#634's sqlite-vec fix), tests_py/handlers/consolidation/test_wiki_maintenance.py and tests_py/handlers/consolidation/test_wiki_backlog_pass.py (#636's fix). tests_py/scripts/test_install_plugin_marker_order.py (#633's fix) is deliberately not added here: it only exists on the still-open fix/issue-633-backend-marker branch, and referencing a nonexistent path would break this job for every unrelated PR until that branch merges. That branch's own PR should add it, matching the same convention. Added one new step, scripts/verify_sqlite_extra_parity.py, run immediately after install-plugin.sh. It parses pyproject.toml's [sqlite] extra directly and checks each declared package resolves as an installed distribution under the real install path's own deps/ directory (importlib.metadata.Distribution.discover, PEP 503 name normalization) -- the direct, minimal check that would have caught #634, since it asserts against the same path a real user's machine goes through, not a CI-only shortcut. An earlier version of this change replaced the curated list with the full suite, doubled the job's timeout with no measured basis, and restructured several steps. Reviewed and rejected: the curated, additive, one-file-per-fix pattern is this job's established convention, not an oversight to correct wholesale, and an unmeasured timeout change is exactly the kind of unsupported figure this repo's own standard forbids. This commit is the targeted rework. ADR-1091 records the decision. Full local pytest (tests_py/scripts/): 1091 passed, 3 skipped. actionlint and a YAML parse both clean on the modified workflow. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MyRfKj1vpBm2yx3sXCN8ik * fix(ci): drop tomllib from verify_sqlite_extra_parity, 3.10 has none PR #640's own Windows CI run caught the bug this commit fixes: Test (Python 3.10) failed at collection with ModuleNotFoundError: No module named 'tomllib'. tomllib is 3.11+ stdlib; this repo's floor is 3.10 (pyproject.toml requires-python), and every ubuntu Test (Python 3.x) matrix leg collects every file under tests_py/, including this PR's own new test file, regardless of which Python version the test itself targets. Replaced tomllib.loads() with a scoped regex extracting the `sqlite = [...]` array's quoted strings directly: pyproject.toml's [sqlite] extra is a short, single-key array, so a general TOML parser was more machinery than the actual parsing need, and this avoids either a version-gated stdlib import or adding a third-party TOML dependency for one list. sqlite_extra_names()'s return value is unchanged for every existing input; all 12 tests in test_verify_sqlite_extra_parity.py still pass against the rewritten implementation. The same CI run's Windows job independently confirmed the new verifier step works as designed: it reported sqlite-vec missing under the real install path's deps/ output, exactly issue #634's defect, live on Windows, on main as it stands today (PR #637 not yet merged). That failure is the check working correctly, not a bug in this PR -- noted here since the two failures landed in the same CI run and only one of them needed a code fix. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MyRfKj1vpBm2yx3sXCN8ik * fix(tests): skip the PG-driver doctor check without psycopg installed CI caught this on Windows once PR #640 added tests_py/test_doctor.py to the curated Windows CI test list: test_pg_driver_passes_in_dev_env asserts _pg_driver().ok is True on the bare assumption "dev env has postgresql extras installed", which doesn't hold on the Windows job's requirements/ci-sqlite-min.txt (deliberately psycopg-free) -- the same assumption is false even in this repo's own local dev venv (psycopg is not importable here either), so this was never actually a dev-only edge case, just never previously exercised. mcp_server/doctor.py's own SQLITE_CHECKS explicitly excludes _pg_driver already, confirming it is not a SQLite-relevant check. Marked with tests_py/conftest.py's existing requires_psycopg marker, the same pattern already used by several sibling test files for exactly this class of dependency. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MyRfKj1vpBm2yx3sXCN8ik --------- Co-authored-by: Claude Sonnet 5 <[email protected]>
Configuration menu - View commit details
-
Copy full SHA for 54677f9 - Browse repository at this point
Copy the full SHA 54677f9View commit details -
chore(release): prepare Cortex 4.23.5 (#641)
Bug-fix release bundling #633 (backend marker discarded on a failed setup.py), #634 (sqlite-vec never installed, neural-vector mislabel), #636 (four wiki maintenance passes silently broken on SQLite), and the Windows CI leg that now actually exercises the SQLite-vec install path and the wiki maintenance fix. Added the missing CHANGELOG entry for #636 (PR #639 never added one) and bumped the 17 version sites across the 13-file version set, verified via scripts/check_version_surfaces.py. Claude-Session: https://claude.ai/code/session_01MyRfKj1vpBm2yx3sXCN8ik Co-authored-by: Claude Sonnet 5 <[email protected]>
Configuration menu - View commit details
-
Copy full SHA for 0037cea - Browse repository at this point
Copy the full SHA 0037ceaView commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff v4.23.4...v4.23.5