Repository navigation
Conversation
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Claude finished @cdeust's task in 2m 40s —— View job Review 1 of 3 (ADR-1119): PR #865
Blockers: none. Checks behind that:
Notes, no action before merge
Posted by updating this comment: Verdict: approve |
…s SQLite (#704) MemorySettings.DATABASE_URL defaulted to postgresql://127.0.0.1:5432/cortex, so library callers with no URL and no marker (CLI-runtime auto, cortex-migrate, the agent-briefing raw connection) reached whatever local cortex database answered. The default is now empty; auto without a named URL is SQLite in every runtime; an explicit postgresql backend with no URL raises; _get_database_url refuses an empty conninfo and cortex-migrate reports it on its exit-1 contract. Refs #704 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP
1ba96df to
4c5a624
Compare
|
Claude finished @cdeust's task in 3m 46s —— View job Review of PR #865 (review 1 of 3)
1 Blocker, which goes against "no silent fallbacks":
There are also 3 one-line Notes: the CHANGELOG and PRIVACY wording claims more than the code does, a branch in Verdict: block |
Review 1/3 — PR #865 (commit 4c5a624)Five reviews ran: quality, security, performance, tests and docs. I checked each candidate finding against the code before listing it. BlockerB1. Standalone store CLIs now silently use an empty SQLite store when the marker says PostgreSQL (breaks the CLAUDE.md rule "no silent fallbacks")
Notes, no action before merge
Verdict: block |
…a URL is SQLite (#704) fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) Review B1 (PR #865, comment 6658250021): portability, migrate and wiki_migrate run as standalone commands and never read the backend marker. With no default URL, a PostgreSQL marker and no URL in the shell gave an empty SQLite store, silently. They now call backend_resolution.settle_for_command first, as mcp_server/__main__.py does. Also: migrate and memory_store docstrings, and the PRIVACY/CHANGELOG wording on which backends use the legacy URL. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP
|
Review on 4c5a624, answered in 749bf05 ( B1, confirmed and fixed. Before this PR, Notes:
Runs: Generated by Claude Code |
|
Claude finished @cdeust's task in 2m 17s —— View job Review 3/3: PR #865 (fixup 749bf05, after 4c5a624)
B1 is fixed. B1 was the standalone CLIs silently building an empty SQLite store when the marker selects PostgreSQL.
Blockers: none. Notes, no action before merge
Merge scopeAll of the PR is accepted: commits 4c5a624 and 749bf05, all 13 files. No Blocker is open and nothing needs a refinement PR. Still open, as the PR body says, and outside this PR: the I posted this by updating this comment, because Verdict: approve |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 749bf05d70
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # source: issue #704 -- no default URL: PostgreSQL is used only when an | ||
| # operator names one (DATABASE_URL / CORTEX_MEMORY_DATABASE_URL) or the | ||
| # backend marker selects it, never because a local default answers. | ||
| DATABASE_URL: str = "" |
There was a problem hiding this comment.
Settle the backend in the remaining maintenance entry points
For an existing local PostgreSQL installation selected by backend.json, with neither URL variable exported, removing this default makes several standalone maintenance commands select SQLite instead of the configured PostgreSQL store. Repository-wide inspection shows that scripts/memory_staleness_revalidate.py:70–79, scripts/memory_reheat.py:47–51, and scripts/memory_dedup_exact.py:42–46 call get_shared_store() without resolving the marker. The staleness command can consequently report success after scanning an empty SQLite database, while the latter commands exit through require_postgres_store() despite PostgreSQL being configured. Apply settle_for_command() before settings/store construction in these remaining entry points, as this change already does for portability and wiki migration.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Confirmed and fixed in 25c27d2 (fixup!).
I swept every standalone entry point that builds the shared store, not only the three named. Nine scripts/ maintenance commands open it through get_shared_store(settings.DB_PATH, …) without reading the marker: backfill_wiki_titles_2026_07_14, backfill_write_class, memory_dedup_exact, memory_domain_backfill, memory_reheat, memory_staleness_revalidate, near_dup_calibrate, provenance_sweep and wiki_citation_seed. Each one now calls settle_for_command(<name>) first, as portability, migrate and wiki_migrate already do, and exits 1 on an invalid marker.
The benchmark harnesses that call PgMemoryStore() with no URL (entity_dedup, decay_sweep_runner) are not changed. They now raise the explicit ValueError instead of reaching a guessed server, and they run against an explicit database (benchmarks/reproduce.sh).
Tests (test_standalone_commands_settle_backend.py):
- a structural check, parametrised over the nine scripts, that the settle call comes before store construction;
- an end-to-end check that
memory_staleness_revalidate.mainwith a PostgreSQL marker and no URL reachespostgresql://localhost:5432/cortex.
With the script changes reverted, 10 of these tests fail; with them, 13 pass. On the touched files ruff check and ruff format --check pass, and check_craftsmanship.py is OK: main in the backfill script went over 40 lines, so store opening moved to _open_store(). tests_py/scripts, handlers/consolidation and invariants: 1958 passed.
Generated by Claude Code
…a URL is SQLite (#704) fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) Codex review on 749bf05 (comment 4480636738): the nine scripts/ maintenance commands that open the shared store (memory_staleness_revalidate, memory_reheat, memory_dedup_exact, and six more) now read the backend marker first through settle_for_command, like portability and migrate. Without it, a PostgreSQL marker with no URL gave them an empty SQLite store. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP
…a URL is SQLite (#704) fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) unit failed on 25c27d2 (run 42031311038, job 127258608806): test_migrate_reports_a_missing_url_on_its_exit_contract. migrate now settles the backend first. The fixture left CORTEX_MEMORY_STORE_BACKEND=postgresql in place: scripts/ci_unit.sh exports it, and tests_py/conftest.py replaces it with sqlite only when PostgreSQL is unreachable, which is why the test passed locally. settle_backend then supplied the legacy URL. The fixture now removes the backend variable, points the marker at an empty temporary methodology directory, and restores the environment whole. Reproduced locally by re-exporting the variable after conftest; passes with the fix. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP
|
Run 42031311038, job 127258608806: 1 failed, 11606 passed. Diagnosis:
Fix (test only): the fixture now removes Evidence:
Not verified: the full suite against a real PostgreSQL, which this session does not have. CI on cc3804d will show it. Generated by Claude Code |
…a URL is SQLite (#704) fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) Mutation gate (ADR-1122) on cc3804d, run 42034218395: kill the survivors in the functions this PR changes. Adds tests for settle_for_command, portability.main, migrate._run, _get_database_url and agent_briefing._connect. settle_for_command moves above the first function: when it was appended after resolve_auto_backend, the diff's trailing blank lines put that untouched function in scope. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP
…a URL is SQLite (#704) fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) Mutation gate (ADR-1122) on cc3804d, run 42034218395: for memory_store.py the stats run died on tests_py/hooks/test_entry.py. The hook subprocess inherits MUTANT_UNDER_TEST and runs mutmut's trampoline in a temp cwd with no [tool.mutmut] config ("Could not figure out where the code to mutate is"). hermetic_hook_env now drops the variable, so the hook process runs the original code and the in-process tests judge the mutants. Any PR that touches a module these hook tests import hits the same failure; the change is also proposed to main separately. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP
|
Run 42034218395, job 127268126994: pytest passed 11607, then 1. Surviving mutants in the functions this PR changes. Test gaps, fixed (4129b86):
2.
Local checks: full suite: 11024 passed, 4 failed, none caused by this PR (3 Not verified: the mutation of Generated by Claude Code |
|
The Generated by Claude Code |
|
Generated by Claude Code |
…a URL is SQLite (#704) fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) unit on f944b6f (run 42042293324, attempt 2): 35 failed, 204 errors, most of them 'no PostgreSQL URL configured' or KeyError 'DATABASE_URL' in later PostgreSQL tests. The no_named_url fixture pops DATABASE_URL, a test then monkeypatch.setenv's it, and monkeypatch's own teardown (which runs after the fixture's full restore) deletes the key it recorded as absent. CI's DATABASE_URL was gone for the rest of the session. Both fixtures now call monkeypatch.undo() before the restore. Reproduced with a probe test after these files (failed before, passes after); a full before/after environment comparison now differs only in PYTEST_CURRENT_TEST. The tree_sitter_language_pack DownloadError failures in the same run are GitHub fetches, not this PR. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP
|
The run ended with 35 failed and 204 errors. The PostgreSQL tests that ran after the new files failed with Cause: the fixture removes Fix: both fixtures ( Evidence:
Not this PR: in the same run, the Generated by Claude Code |
|
CI autopilot: PR on hold. On 129beff, the mutation gate hangs on Run 42044899519, job 127305210538:
What I know:
What a human needs to decide or do:
Everything else on this PR is green or verified. Commits pushed since the last review: 4129b86, f944b6f, 129beff. Generated by Claude Code |
…ER_TEST (ADR-1122) (#889) Under the mutation gate, hook tests start the hook as a subprocess whose cwd is a temporary project. The subprocess inherits MUTANT_UNDER_TEST, so mutmut's trampoline looks for [tool.mutmut] in that cwd and aborts ("Could not figure out where the code to mutate is"). The hook prints "Cortex not ready", tests_py/hooks/test_entry.py fails, and the gate's stats run stops for any PR that changes a module those tests import (seen on #865, run 42034218395, memory_store.py). hermetic_hook_env now drops the variable: the hook process runs the original code, and the in-process tests judge the mutants. Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP Co-authored-by: Claude <[email protected]>
…e (ADR-1122) (#898) * ci: run only the mutants of the changed functions in the mutation gate (ADR-1122) mutation_check.sh ran `mutmut run` with no name, so mutmut ran every mutant of each changed file and the gate judged the changed functions afterwards. #865 (backend_resolution.py, 262 mutants) was cancelled at the six-hour job limit after 141; #877 ran past two hours. The script now passes one `<prefix>*` name per changed function (scripts/ci_mutation_scope.py --globs). mutmut 3.8.1 asserts when no mutant matches; after a failed run the gate passes only when mutmut's stats file exists and its .meta files hold no mutant in scope, any other failure fails the job. Without MUTATION_ONLY_PREFIXES, every mutant runs as before. Measured on #877's diff (local macOS arm64, PostgreSQL 18.6): 36 mutants instead of 1,164, verdict in 21 min 15 s. No mutant hit mutmut's CPU timeout, so no wall-clock cap is added. * test(ci): keep the mutation scope test helper within four parameters * ci: fail loudly when the glob helper fails, and require each target's meta for an empty scope Review 1 of #898 notes: - A failure of `ci_mutation_scope.py --globs` inside `< <(...)` did not stop the script: NAMES stayed empty and every mutant ran. The names are now read from an assignment, so `set -e` stops the gate. - `--empty-scope` passed when the mutated file's `.meta` was missing. It now takes the mutated files and concludes only when each `.meta` exists; an empty file list is a usage error. - The shell tests used rc=1 for the fake failures; they now use 3, so the script must forward mutmut's own exit code.
|
Hold levé : f9f8074 (#898), fusionné sur Generated by Claude Code |
|
CI autopilot : rebase prêt localement, push refusé par cette session ; remise en hold.
À faire par un humain : Generated by Claude Code |
…(300-line cap) They test backend_resolution.settle_for_command, not a standalone command; the move brings test_standalone_commands_settle_backend.py from 301 to 263 lines.
|
Hold Generated by Claude Code |
…a URL is SQLite (#704) Check unit, run 42204224811 (32ad0ff): the ADR-1122 mutation gate left 122 survivors in the changed functions of memory_store.py (_construct_store 102, _resolve_backend_url 16, _database_url_is_explicit 4). No test pinned the selection's outcomes: which store, path and dimension, which URL is tried, and the exact operator-facing error and warning texts. test_construct_store_selection.py pins every branch with PostgreSQL and SQLite replaced by recorders. Two code changes remove mutants no test can kill: the strict-failure message no longer carries the dead `url or '<unset>'` (url is non-empty there since #704 raises first), and os.environ.get("DATABASE_URL") drops a "" default that `or` made equivalent to None. The two remaining CORTEX_ALLOW_SQLITE_FALLBACK default mutants are registered equivalents. Local gate (mutation_check.sh, main's gate scripts, forkserver, only this test file): 187 in-scope mutants, 185 killed, 2 registered equivalents. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtrWzv6PGpJnXKSYPs
|
CI autopilot : correctif du gate de mutation poussé en Diagnostic. Run 42204224811 sur Correctif (
Reçus locaux (Linux x86_64, Python 3.11, sans torch ni PostgreSQL) :
Non vérifié :
La branche a 5 commits de retard sur Generated by Claude Code |
…tabase-url # Conflicts: # memory/mutation-equivalents.json
…tabase-url # Conflicts: # memory/mutation-equivalents.json
|
Claude finished @cdeust's task in 4m 32s —— View job Review 4 (past the ADR-1119 cap of 3): PR #865, commits after 749bf05
B1 is still fixed. BlockerB2. The 25c27d2 sweep missed three commands. They still fall back silently to an empty SQLite store when the marker selects PostgreSQL (breaks the CLAUDE.md rule "no silent fallbacks", same failure as B1)
Checked and fine:
Notes, no action before merge
Merge scope
Not verified:
Verdict: block |
…ore a handler opens the store (#704) PR #865 review 4 (B2): scripts/groomer.py, scripts/cortex_ingest.py and scripts/dev_run_ingest.py reach get_shared_store through handlers (get_grooming_health, curate_distill, ingest_codebase) and never called settle_for_command. With a PostgreSQL marker and no DATABASE_URL (the documented launchd groomer job), they used an empty SQLite store, silently. Each entry point now settles first and exits 1 when it cannot. The earlier sweep relied on a list kept by hand. A new test scans scripts/ and requires settle_for_command in every script that imports a handler or the store, with the two exemptions explained in the test. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP
|
Review 4 on d034c79, answered in 21fbc2f. B2: confirmed and fixed. Root cause, not just these three: the 25c27d2 sweep relied on a list kept by hand. The new
Checks:
Notes: the raw URL printed in Generated by Claude Code |
…122 item 6) (#917) Owner decision 2026-11-06. mutmut names mutants by function, so the gate ran and judged every mutant of each changed function: a one-line change owned the whole function's survivors (#865: 102 in _construct_store; #878: 273 on the recall path). scripts/ci_mutation_lines.py places each mutant on the source by diffing it against mutmut's unmutated copy of the function, both indexed in mutants/<path>.spans, and keeps it when it alters a line the PR changed (or the anchor of a deletion and the next line). plan() gives each job its lines; run_job passes them as MUTATION_ONLY_LINES; the --untested check and mutation_equivalents.py judge only the kept mutants, so registry entries on other lines are not stale. A mutant that cannot be placed stops the gate. Checked against mutmut show on all 245 mutants of core/telemetry.py and all 35 of core/wiki_identity.py (methods included). End to end on a one-line change to publish_record (PostgreSQL 18.6): 38 mutants ran, 20 survived on untouched lines, the gate passes and reports them as not judged.
|
CI autopilot : branche en retard de 2 commits sur Note : la branche contient des commits Generated by Claude Code |
|
CI autopilot : branche toujours en retard sur J'ai préparé la mise à jour en local sans pouvoir la pousser : la session autopilot a refusé le Pour la personne qui rebasera : un Vérifié en local sur ce commit : Generated by Claude Code |
|
CI autopilot : rebase sur La branche a 15 commits de retard sur
Après rebase : 3 commits, 150 tests de la PR et Le push Generated by Claude Code |
|
Remplacée par #937 : même commit de tête ( |
…s SQLite (#704, slice 2) (#937) * fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) MemorySettings.DATABASE_URL defaulted to postgresql://127.0.0.1:5432/cortex, so library callers with no URL and no marker (CLI-runtime auto, cortex-migrate, the agent-briefing raw connection) reached whatever local cortex database answered. The default is now empty; auto without a named URL is SQLite in every runtime; an explicit postgresql backend with no URL raises; _get_database_url refuses an empty conninfo and cortex-migrate reports it on its exit-1 contract. Refs #704 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP * fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) Review B1 (PR #865, comment 6658250021): portability, migrate and wiki_migrate run as standalone commands and never read the backend marker. With no default URL, a PostgreSQL marker and no URL in the shell gave an empty SQLite store, silently. They now call backend_resolution.settle_for_command first, as mcp_server/__main__.py does. Also: migrate and memory_store docstrings, and the PRIVACY/CHANGELOG wording on which backends use the legacy URL. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP * fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) Codex review on 749bf05 (comment 4480636738): the nine scripts/ maintenance commands that open the shared store (memory_staleness_revalidate, memory_reheat, memory_dedup_exact, and six more) now read the backend marker first through settle_for_command, like portability and migrate. Without it, a PostgreSQL marker with no URL gave them an empty SQLite store. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP * fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) unit failed on 25c27d2 (run 42031311038, job 127258608806): test_migrate_reports_a_missing_url_on_its_exit_contract. migrate now settles the backend first. The fixture left CORTEX_MEMORY_STORE_BACKEND=postgresql in place: scripts/ci_unit.sh exports it, and tests_py/conftest.py replaces it with sqlite only when PostgreSQL is unreachable, which is why the test passed locally. settle_backend then supplied the legacy URL. The fixture now removes the backend variable, points the marker at an empty temporary methodology directory, and restores the environment whole. Reproduced locally by re-exporting the variable after conftest; passes with the fix. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP * fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) Mutation gate (ADR-1122) on cc3804d, run 42034218395: kill the survivors in the functions this PR changes. Adds tests for settle_for_command, portability.main, migrate._run, _get_database_url and agent_briefing._connect. settle_for_command moves above the first function: when it was appended after resolve_auto_backend, the diff's trailing blank lines put that untouched function in scope. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP * fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) Mutation gate (ADR-1122) on cc3804d, run 42034218395: for memory_store.py the stats run died on tests_py/hooks/test_entry.py. The hook subprocess inherits MUTANT_UNDER_TEST and runs mutmut's trampoline in a temp cwd with no [tool.mutmut] config ("Could not figure out where the code to mutate is"). hermetic_hook_env now drops the variable, so the hook process runs the original code and the in-process tests judge the mutants. Any PR that touches a module these hook tests import hits the same failure; the change is also proposed to main separately. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP * fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) unit on f944b6f (run 42042293324, attempt 2): 35 failed, 204 errors, most of them 'no PostgreSQL URL configured' or KeyError 'DATABASE_URL' in later PostgreSQL tests. The no_named_url fixture pops DATABASE_URL, a test then monkeypatch.setenv's it, and monkeypatch's own teardown (which runs after the fixture's full restore) deletes the key it recorded as absent. CI's DATABASE_URL was gone for the rest of the session. Both fixtures now call monkeypatch.undo() before the restore. Reproduced with a probe test after these files (failed before, passes after); a full before/after environment comparison now differs only in PYTEST_CURRENT_TEST. The tree_sitter_language_pack DownloadError failures in the same run are GitHub fetches, not this PR. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP * test: move the settle_for_command tests next to backend_resolution's (300-line cap) They test backend_resolution.settle_for_command, not a standalone command; the move brings test_standalone_commands_settle_backend.py from 301 to 263 lines. * fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) Check unit, run 42204224811 (32ad0ff): the ADR-1122 mutation gate left 122 survivors in the changed functions of memory_store.py (_construct_store 102, _resolve_backend_url 16, _database_url_is_explicit 4). No test pinned the selection's outcomes: which store, path and dimension, which URL is tried, and the exact operator-facing error and warning texts. test_construct_store_selection.py pins every branch with PostgreSQL and SQLite replaced by recorders. Two code changes remove mutants no test can kill: the strict-failure message no longer carries the dead `url or '<unset>'` (url is non-empty there since #704 raises first), and os.environ.get("DATABASE_URL") drops a "" default that `or` made equivalent to None. The two remaining CORTEX_ALLOW_SQLITE_FALLBACK default mutants are registered equivalents. Local gate (mutation_check.sh, main's gate scripts, forkserver, only this test file): 187 in-scope mutants, 185 killed, 2 registered equivalents. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtrWzv6PGpJnXKSYPs * fix(scripts): groomer and ingest commands read the backend marker before a handler opens the store (#704) PR #865 review 4 (B2): scripts/groomer.py, scripts/cortex_ingest.py and scripts/dev_run_ingest.py reach get_shared_store through handlers (get_grooming_health, curate_distill, ingest_codebase) and never called settle_for_command. With a PostgreSQL marker and no DATABASE_URL (the documented launchd groomer job), they used an empty SQLite store, silently. Each entry point now settles first and exits 1 when it cannot. The earlier sweep relied on a list kept by hand. A new test scans scripts/ and requires settle_for_command in every script that imports a handler or the store, with the two exemptions explained in the test. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_018kyZYtyFK1iv4S9wZDjGoP * fixup! fix(storage): no default PostgreSQL URL in code; auto without a URL is SQLite (#704) Review 1 of #937, blocker: PRIVACY.md said that with neither DATABASE_URL nor a marker Cortex opens no PostgreSQL connection. That holds on a fresh install only: on a HOME with earlier Cortex state and no marker, settle_backend -> persist_first_decision -> decide probes localhost:5432 once and selects PostgreSQL when something answers or the answer is unclear, then writes the marker (ADR-1104). The text now says both. --------- Co-authored-by: Claude <[email protected]>
Summary
Library residual of #704, named out of scope by #804 (
docs/verification/draft-relevance-20261027.md§ 770):MemorySettings.DATABASE_URLstill defaulted topostgresql://127.0.0.1:5432/cortex. Every library path that reads the setting without a named URL could therefore reach a localcortexdatabase nobody configured:_construct_storewith thecliruntime mappedautotopostgresqland tried the default URL;python -m mcp_server.migrateconnected to it (RED reproduced:connection to server at "127.0.0.1", port 5432 failed);agent_briefing_query._connectpassed it to rawpg_connectwhen no backend was decided.Root cause: the default URL in
memory_config.py. It is now empty, and the callers follow an explicit contract:autowith no named URL → SQLite in every runtime, with no connection attempted (_resolve_backend_urlfollows the same rule, so the cache key stays consistent);postgresqlbackend with no URL →RuntimeError(no silent SQLite store, no guessed server; the oldallow_fallback = not urlbranch disappears);pg_store_ddl._get_database_urlrefuses an empty conninfo (ValueError), because libpq would then connect to its local defaults;cortex-migratereports it on its exit-1 contract;postgresqlwithout a URL, nothing is opened.PRIVACY.md is corrected: it promised a "default
postgresql://127.0.0.1:5432/cortex". The marker path keeps ADR-1104's legacy URL insettle_backend, and the text says so.Refs #704 (not
Closes: see "Breaking changes / remaining work").Type of change
Test plan
tests_py/infrastructure/test_no_default_database_url.py, 10 tests: 9 fail onorigin/main(1de07f9) and 10 pass with the fix. Every_try_pg_verbose/pg_connectcall fails the test, so any connection attempt is caught.test_sqlite_backend.py::test_reachable_postgresql_is_preferred_over_sqliteasserted exactly the behaviour A profile with no configuration connects to a local PostgreSQL it was never configured for #704 rejects (a default URL that answers wins). It now names its URL throughCORTEX_MEMORY_DATABASE_URL.test_no_default_database_url,test_sqlite_backend,test_backend_resolution,hooks/test_entry_fresh_backend,test_shared_backend_bootstrap,hooks/test_agent_briefing*,test_migrate→ 122 passed, 8 skipped (PostgreSQL absent).pytest tests_py: 10904 passed, 624 skipped, 4 failed, none caused by this PR: 3test_embedding_engine(torchnot installable here, its download host is blocked) andtest_wiki_coverage_dashboard::test_unreadable_page_is_skipped_not_fatal, which also fails onorigin/main(the session runs as root, so "unreadable" files can be read).ruff check/ruff format --check(0.17.3, fromuv.lock) pass on the touched files (main has 15 E501/E741 errors elsewhere).scripts/check_craftsmanship.py: OK.Audit notes
Breaking changes
auto, migrate, briefing) connected topostgresql://127.0.0.1:5432/cortex.auto), or an explicit error (postgresqlbackend, migrate). Migration: setDATABASE_URLorCORTEX_MEMORY_DATABASE_URL.scripts/install-plugin.sh(lines 20–21, 87) still selects PostgreSQL at install time when it finds a reachable localcortexdatabase ("never downgrade"). Removing that choice changes upgrades for existing PostgreSQL installs, so it is a product decision, not part of this PR.Reviewer checklist
Generated by Claude Code