Skip to content

fix: align Claude and Codex backend selection and verify shared handoff - #600

Merged
cdeust merged 3 commits into
mainfrom
feat/shared-host-decisions
Sep 17, 2026
Merged

cdeust merged 3 commits into
mainfrom
feat/shared-host-decisions

Conversation

@cdeust

@cdeust cdeust commented Sep 16, 2026

Copy link
Copy Markdown
Owner

Summary

Direct Cortex MCP startup now applies the saved backend selection before settings-dependent imports, matching the Claude launcher. Previously, a saved SQLite selection could be honoured by Claude while the Codex console entry point selected a reachable PostgreSQL server, sending the two hosts to different stores.

Adds independent-process tests for shared SQLite persistence and project ADR handoff, plus documentation of the common storage/root contract. The Codex plugin retains its existing ten-tool lean profile; ADR authoring requires an explicitly configured full-profile server.

Type of change

  • Bug fix (non-breaking)
  • Supporting tests and documentation

Test plan

  • New tests: 12 passed (bootstrap selection, real MCP project ADR calls, independent SQLite processes).
  • Related existing tests: 47 passed (backend marker, launcher resolution, tool profiles, ADR identity).
  • Regression baseline: 4 of 9 bootstrap cases failed before the fix, all nine pass afterward.
  • Ruff lint and formatting, explicit five-file craftsmanship gate, and git diff --check: passed.

Commands, using the repository Python environment and CORTEX_MEMORY_STORE_BACKEND=sqlite:

python -m pytest -q tests_py/test_shared_backend_bootstrap.py tests_py/test_shared_host_decisions.py tests_py/infrastructure/test_shared_host_store.py
python -m pytest -q tests_py/infrastructure/test_backend_marker.py tests_py/scripts/test_launcher_resolution.py tests_py/test_tool_profiles.py tests_py/handlers/test_wiki_adr_identity.py

Tests cover exact ADR retrieval, denied lean authoring, explicitly linked follow-up decisions, concurrent ADR submissions, separation between explicit project roots, visibility of acknowledged SQLite writes, and persistence after reopening. Child processes have bounded protocol waits and cleanup.

The full suite has not been run locally. These are local macOS/POSIX results, not Windows coverage. Installed Claude/Codex clients, semantic retrieval quality, PostgreSQL handoff, global ADR-to-database pointer integration, and automatic host capture remain outside this verification. Concurrent submissions do not prove every possible race absent. No mutation campaign was run.

Audit notes

  • Independent engineering review found missing subprocess deadlines/cleanup; fixed and re-reviewed with an APPROVE verdict for the bounded scope.
  • Formal Zetetic team review: pending, arranged by the owner.
  • Follow-up acceptance: run both installed hosts against disposable shared data, including explicit ADR authoring configuration. This PR does not claim marketplace readiness.

Coding-standards compliance

Production change reuses the existing ADR-0505 resolver before settings load; explicit backend, alias, and database URL precedence remain unchanged. No new retrieval algorithm or tuning constant. Test timeout budgets are documented as liveness limits. Layer/size/source checks passed the craftsmanship gate.

Breaking changes

No tool-profile or schema changes. Direct startup now honours an existing saved backend selection when no higher-priority override is supplied. Users who previously relied on that selection being ignored should configure their intended backend explicitly. Existing stores are not migrated or merged.

Screenshots / logs

The checks and limitations are documented in docs/shared-host-memory.md. Tests use disposable roots; no live host configuration or personal memory data is part of the diff.

Reviewer checklist

  • CHANGELOG entry, if required before merge.
  • Documentation updated.
  • No credentials or personal memory data included.
  • CI passes on the latest commit.
  • Owner's Zetetic review completed.

@cdeust

cdeust commented Sep 16, 2026

Copy link
Copy Markdown
Owner Author

ZETETIC-REVIEW: APPROVE

Reviewed at head db22b16 (branch feat/shared-host-decisions to main) in an isolated worktree (.claude/worktrees/review-600, removed after review). Treated the PR body's claims as unverified and reproduced each one from a fresh Python interpreter, subprocess, or full pytest run.

Move 0: Ledger / seen-defect check

No un-issued seen-defect rationalizations found. The body explicitly enumerates what it does NOT cover ("full suite has not been run locally", "no Windows coverage", "no PostgreSQL handoff", "no mutation campaign") without dismissing any observed defect. These are honest scope disclaimers, not bypassed failures. Proceeding.

Stakes: Medium

Touches a production entry point (mcp_server/__main__.py, 6 non-comment lines) that runs on every direct/console launch, but the change is a narrow env-resolution call reusing an already-reviewed resolver (ADR-0505). No schema, no public API, no auth/billing surface. Full Moves 1 through 4 applied; Moves 5 and 6 at the touched lines.

1. Import-time side effect: verified safe, evidence below

apply_backend_resolution(os.environ) at mcp_server/__main__.py:20 is a genuine top-level call statement between imports (not an if/try/with, which pycodestyle already special-cases). Confirmed with the file-wide noqa stripped:

UV_NO_SYNC=1 uv run ruff check --select E402 --no-cache <copy>
-> 14 E402 errors, all on the 14 pre-existing downstream `from mcp_server...` imports (lines 37 to 66)

So the suppression is exactly as narrow as it can be. It hides nothing new; it only re-permits imports that were already only accidentally exempt (via the try/except scipy-preload block) before this call was inserted. Scoped to E402 only, not a bare # ruff: noqa, so no other rule is silenced.

Does importing mcp_server.__main__ mutate ambient os.environ? Yes, when a real marker file is present. That is the intended feature (matches launcher.py's existing behavior per ADR-0505). Does that leak across tests?

  • tests_py/conftest.py:39-54 sets CORTEX_CLAUDE_DIR to a fresh tempfile.mkdtemp() before any mcp_server module is imported (module-level code, guaranteed to run before pytest collection imports tests_py/test_main.py:10 or tests_py/handlers/test_tool_schema_parity.py:39, both of which import mcp_server.__main__ at module scope).
  • Reproduced directly: with CORTEX_CLAUDE_DIR=/tmp/fake_claude_dir pre-set in the shell (containing a real {"backend":"postgresql"} marker) before invoking pytest, the suite still resolves auto. Conftest's unconditional overwrite wins, confirming the "developer's real environment" scenario the task asked me to check.
  • Grepped tests_py/ for any module-level write to $CORTEX_CLAUDE_DIR/methodology/backend.json: none exists (only tests_py/infrastructure/test_backend_marker.py uses an explicit tmp_path / "backend.json", never the shared conftest tempdir). Since pytest imports all test modules during collection before executing any test body, no marker file can exist in the shared tempdir at the moment mcp_server.__main__ is first imported, so resolve_backend_env returns {} every time in-process. Ran the full suite (below) with zero failures, consistent with this.
  • The three new PR test modules never rely on the in-process import mutation at all. They spawn subprocesses (subprocess.Popen/subprocess.run) with their own explicit env= dict, so the parent test-runner's os.environ is never touched by them either.

Verdict: no observed or theoretically reachable cross-test leakage. docs/shared-host-memory.md and the module docstring in backend_marker.py correctly describe the mutation as intentional plugin behavior, not a testing hazard.

2. Precedence: verified against backend_marker.py and reproduced

mcp_server/infrastructure/backend_marker.py:11-19,65-82 implements exactly the 5-step precedence the docs claim. Reproduced each step live via tests_py/test_shared_backend_bootstrap.py (all 9 cases pass at head; see section 4) plus a direct read of resolve_backend_env:

  • CORTEX_MEMORY_STORE_BACKEND set: returns {} untouched (line 71-72).
  • CORTEX_BACKEND=postgres|postgresql|sqlite: mapped via _BACKEND_ALIASES and returned (line 73-75).
  • Non-empty DATABASE_URL / CORTEX_MEMORY_DATABASE_URL: returns {} untouched (line 76-79). Explicit DSN wins over the marker.
  • Marker file backend: applied (line 80-81).
  • Nothing: {}, engine default auto (line 82).
  • The claim that an explicit but unreachable PostgreSQL DSN stays an error rather than silently redirecting to SQLite is a property of memory_store._construct_store's strict no-silent-fallback path (referenced, not reimplemented, by this module). This PR does not touch that code, and the docs correctly attribute the guarantee to the existing engine, not to this change.
  • Blank-DSN normalization (apply_backend_resolution lines 100-102, deleting a whitespace-only DATABASE_URL) is exercised by test_blank_manifest_dsn_does_not_override_marker, which passed at head and failed on main (section 4).

3. # ruff: noqa: E402

Narrowest possible suppression: see section 1. Confirmed it does not mask any other genuine late-import problem beyond the 14 lines that were already structurally "late" and only escaped ruff by the try/except exemption. No repo precedent for a file-wide suppression elsewhere (grep -rl "# ruff: noqa: E402" finds only this file), but 14 individually tagged noqas would be noisier for no safety benefit here. Not blocking.

4. New tests: reproduced the regression number and ran everything

  • "4 of 9 bootstrap cases failed before the fix": reproduced exactly. Copied tests_py/test_shared_backend_bootstrap.py into a fresh git worktree checked out at origin/main (i.e. mcp_server/__main__.py without the apply_backend_resolution call) and ran it: 4 failed, 5 passed, the same 4 tests the PR would name (test_direct_entrypoint_applies_saved_backend_before_settings[sqlite], [postgresql], test_explicit_backend_takes_precedence_over_marker[overrides1] i.e. CORTEX_BACKEND=postgres, test_blank_manifest_dsn_does_not_override_marker). At head (PR code), all 9 pass.
  • tests_py/test_shared_backend_bootstrap.py, tests_py/test_shared_host_decisions.py, tests_py/infrastructure/test_shared_host_store.py: ran directly, 12 passed (matches the claim).
  • Full suite (UV_NO_SYNC=1 CORTEX_MEMORY_STORE_BACKEND=sqlite uv run pytest -q, 453.51s): 8670 passed, 91 skipped, 0 failed, 459 subtests passed. The PR body's "full suite has not been run locally" is now closed out by this review run; no regressions anywhere in the tree.
  • Subprocess bounding/cleanup: tests_py/infrastructure/test_shared_host_store.py:282-294 (_stop) does wait, terminate, wait, kill, wait with CLEANUP_TIMEOUT=5 at each stage, closes stdout, and asserts returncode == 0 only on the non-exception path. _readline/_exchange use select.select with a 30s deadline, no unbounded blocking reads. tests_py/test_shared_backend_bootstrap.py uses subprocess.run(..., timeout=30). tests_py/test_shared_host_decisions.py wraps its async scenarios in asyncio.wait_for(..., timeout=90) and uses the MCP Client context manager for process teardown. Checked for orphans after every run (ps aux | grep shared_host_store_worker / mcp_server --profile): none left running.
  • None of the three new test modules reach a real PostgreSQL; they hardcode CORTEX_MEMORY_STORE_BACKEND=sqlite in the spawned child env.
  • Real ~/.claude tree: stat-checked ~/.claude/methodology/backend.json and memory.db mtimes before and after the full local run; both unchanged (backend.json last modified about 23h before this review, unrelated to any command run here). tests_py/conftest.py's CORTEX_CLAUDE_DIR redirect (verified in section 1) also protects the in-process tests; the new subprocess tests additionally pass their own CORTEX_CLAUDE_DIR=<tmp_path> per worker, so even a bug in conftest would not let them fall through to the real tree.

5. Interaction with PR #599 (feat/prediction-records, open)

PR #599 touches mcp_server/__main__.py at lines ~42-46 (adds tool_registry_predictions import) and ~101-119 (registers it in merged_schemas/register_all), both well below and structurally disjoint from PR #600's insertion at lines 9-20. Simulated the merge directly (scratch git clone, checked out origin/feat/prediction-records, git merge origin/feat/shared-host-decisions): clean auto-merge, zero conflicts, in both directions of the pairwise test. Recommend merging #600 first (smaller, narrower diff, already fully green here) then rebasing/merging #599 on top, but either order merges cleanly. This is a preference, not a blocker.

6. Project gates

All run from the isolated worktree, uv sync --no-default-groups --extra dev --extra postgresql --extra sqlite --extra codebase --extra otel --group typecheck:

  • ruff check .: all checks passed.
  • ruff format --check .: 1472 files already formatted.
  • python scripts/check_craftsmanship.py --base origin/main: OK.
  • python scripts/check_doc_claims.py: OK (1 pre-existing declared exemption, unrelated to this PR).
  • python scripts/check_project_wiki.py: mirrors match canonical sources.
  • pyright: 0 errors, 0 warnings, 0 informations.
  • pytest -q (full suite): 8670 passed, 91 skipped, 0 failed (453.51s). This closes the "full suite has not been run locally" gap the PR body flagged.

7. Doc claims vs. test coverage

docs/shared-host-memory.md is unusually well-hedged for a Codex-authored doc. Every claim I checked against the diff is either (a) directly reproduced by a test in this PR, or (b) explicitly disclaimed as untested ("cross-process PostgreSQL handoff is not covered by the new SQLite tests", "does not establish... equivalent Claude and Codex lifecycle hooks", "Project-root separation is a routing check, not an authorization boundary", "no live host configuration... is changed here"). I did not find a claim stated as established behavior that the tests fail to back up. docs/codex-plugin.md's precedence rewrite (lines 9-27) matches backend_marker.py exactly (section 2). ADR-0505, ADR-0056, and ADR-0693 citations all resolve to real, existing ADRs (docs/adr/ADR-0505-backend-marker.md, ADR-0056-wiki-decisions-and-reviewable-mirrors.md, ADR-0693-mcp-server-tool-profiles.md). No fabricated citations.

8. ADR / CHANGELOG

Non-blocking observation, not a demonstrated defect: the last 5 merged PRs on main (commits 0fc6bd1a, 10b98d08, 6a7e2550, a981f935, d548fc1e) each added both a new sequential docs/adr/ADR-10NN-*.md entry and a CHANGELOG.md section. This PR adds neither, and its own checklist leaves both boxes unticked. The change is a legitimate behavior change to a production entry point (developers running python -m mcp_server directly, or the Codex plugin's direct console path, now get the saved backend applied where they previously did not). It is not purely a test/doc PR. Whether this rises to "needs its own ADR number" vs. "already covered by ADR-0505 extending its enforcement point" is the owner's call; I did not find a repo rule making a new ADR number mandatory (no CI gate enforces it: decision_gate.py is a commit-time hook, not a CI check), but the 5/5 recent-precedent pattern plus the PR's own unticked checkbox is worth resolving before or shortly after merge. Not blocking: no rule was violated, no defect demonstrated.

Findings

Blocking

None.

Non-blocking

  • mcp_server/__main__.py:9: file-wide # ruff: noqa: E402 has no repo precedent. Confirmed narrowly scoped and necessary (sections 1 and 3), but a short comment noting why the noqa is file-wide rather than per-line would save the next reader the investigation.
  • Repo convention (last 5 merged PRs) pairs every behavior change with a new docs/adr/ADR-10NN-*.md and CHANGELOG.md entry; this PR has neither and its own checklist leaves both unticked (section 8). Recommend the owner decide whether ADR-0505 already covers this extension or a new ADR/CHANGELOG entry is expected before merge.
  • docs/shared-host-memory.md and docs/codex-plugin.md both say "In this source checkout (pending release)" / "must be released first": good practice, no change requested.

Commands run

git worktree add .claude/worktrees/review-600 db22b167
uv sync --no-default-groups --extra dev --extra postgresql --extra sqlite --extra codebase --extra otel --group typecheck
UV_NO_SYNC=1 uv run ruff check .
UV_NO_SYNC=1 uv run ruff format --check .
UV_NO_SYNC=1 uv run python scripts/check_craftsmanship.py --base origin/main
UV_NO_SYNC=1 uv run python scripts/check_doc_claims.py
UV_NO_SYNC=1 uv run python scripts/check_project_wiki.py
UV_NO_SYNC=1 uv run pyright
UV_NO_SYNC=1 CORTEX_MEMORY_STORE_BACKEND=sqlite uv run pytest -q            # full suite: 8670 passed, 91 skipped
UV_NO_SYNC=1 CORTEX_MEMORY_STORE_BACKEND=sqlite uv run pytest -q tests_py/test_shared_backend_bootstrap.py -v   # 9 passed
UV_NO_SYNC=1 CORTEX_MEMORY_STORE_BACKEND=sqlite uv run pytest -q tests_py/infrastructure/test_shared_host_store.py tests_py/test_shared_host_decisions.py -v  # 3 passed
# baseline reproduction: copied test_shared_backend_bootstrap.py into a worktree at origin/main
# (mcp_server/__main__.py without apply_backend_resolution) -> 4 failed, 5 passed
UV_NO_SYNC=1 uv run ruff check --select E402 --no-cache <copy of __main__.py with the file-wide noqa stripped>  # 14 errors, all pre-existing downstream imports
git clone (scratch); checkout origin/feat/prediction-records; git merge origin/feat/shared-host-decisions   # clean, 0 conflicts

Verdict

APPROVE. Every claim in the PR body that I could independently verify was reproduced exactly (the 4/9 regression count, the 12+47 test counts, the precedence chain, the merge compatibility with #599). The full suite (not run by the author) passes cleanly at 8670/0. No security, layering, wiring, or test-adequacy defects found. The two non-blocking items (file-wide noqa comment, missing ADR/CHANGELOG per recent convention) do not block merge.

@cdeust

cdeust commented Sep 16, 2026

Copy link
Copy Markdown
Owner Author

Review verdict is APPROVE (see the review comment above). Two things are missing before this merges, both repo convention rather than defects, and the owner's call is that this branch carries them.

An ADR. Every decision of this kind is recorded as a wiki ADR, and the last five PRs merged to main each added one. ADR-0505 covers resolving the saved backend selection in scripts/launcher.py; this PR extends that decision to the direct console and module entry point, which is a decision of its own: it changes what a bare python -m mcp_server does for anyone who has a saved selection, and it makes an import mutate the process environment. Write it with the wiki_adr tool, passing project_root as this checkout, which writes wiki/adr/cortex/<n>-<slug>.md, its docs/adr/ADR-<n>-... mirror and the wiki/manifest.json entry in one call. The next free number is 1078 as of ADR-1077, so take whatever wiki_adr allocates rather than assuming one. Worth stating in it: the precedence chain, the reason the import runs before the settings-dependent imports, and the fact that the file-wide # ruff: noqa: E402 is scoped to E402 only and covers fourteen pre-existing imports (the review measured that).

A CHANGELOG entry, under ## [Unreleased] / ### Fixed, naming the symptom rather than the patch: a saved SQLite selection honoured by the Claude launcher while the direct entry point could pick a reachable PostgreSQL server, sending the two hosts to different stores.

One non-blocking nit from the review worth folding in while you are there: the file-wide # ruff: noqa: E402 has no precedent in this repository, so a one-line comment saying why it is file-wide rather than per-import would save the next reader the measurement.

Unrelated to the diff, and already handled on my side: this branch's worktree sits at .Codex/worktrees/shared-host-decisions, outside .claude/worktrees/ where the project's standing rule puts every worktree, and .Codex was not gitignored, so it was one git add -A away from being committed. The owner chose to ignore the path rather than move the worktree; a separate PR adds .Codex/ to .gitignore.

@cdeust

cdeust commented Sep 16, 2026

Copy link
Copy Markdown
Owner Author

The ADR and the CHANGELOG entry are there, thank you. One blocking collision before this can merge, and it is not about the content.

ADR-1076 is taken. PR #599 (feat/prediction-records, open, approved, CI green) allocates ADR-1076 to "A prediction is written open and resolved against evidence the caller supplies" and ADR-1077 to "The advertised tool count is read from the registries". Both numbers are already woven through that branch's source: ADR-1076 is cited in mcp_server/core/calibration.py, handlers/predict.py, handlers/resolve_prediction.py, handlers/calibration.py, infrastructure/prediction_store.py and infrastructure/sqlite_schema_predictions.py, and ADR-1077 in mcp_server/tool_surface.py and scripts/verify_mcp_hosts.py.

Both branches took 1076 because both were cut when main topped out at ADR-1075, and wiki_adr allocates from the manifest of the checkout it runs in, which cannot see an unmerged sibling. Whichever merges second lands a duplicate identifier in a space the project treats as unique (issue #514: the wiki id is the only decision index), plus a textual conflict in wiki/manifest.json, since both insert immediately after the ADR-1075 entry.

The cheaper renumber is yours: 1078, or whatever wiki_adr allocates once #599 has merged. Your number appears in the ADR page, its docs/adr mirror, the manifest entry and docs/shared-host-memory.md; mine appears in eight source files. If you would rather keep 1076, say so and I will renumber #599 instead, but it is more edits and more places to miss one.

Renumbering by hand means the page, the mirror (including its generated header comment), the number: front-matter field, the wiki/manifest.json key and every citation. scripts/check_project_wiki.py verifies the mirror matches the canonical page afterwards.

On merge order once that is settled: the two branches merge cleanly in either order, verified on a scratch clone before your update, with disjoint line ranges in mcp_server/__main__.py. The manifest conflict above is the only interaction, and it disappears as soon as the numbers differ.

The file-wide noqa now carries its reason, which answers the review's nit.

I am re-running the review on this head, since the previous verdict was posted on db22b167 and the merge gate refuses a verdict older than the head.

@cdeust

cdeust commented Sep 16, 2026

Copy link
Copy Markdown
Owner Author

ZETETIC-REVIEW: REQUEST_CHANGES

Re-verified at new head fe45317 (previous review was on db22b16, posted as #600 (comment), APPROVE). This is a fresh pass, not a diff of my old comment. Worked in .claude/worktrees/review-600-v2, removed after review; nothing edited, committed, or pushed.

What changed since db22b16

CHANGELOG.md (+7), docs/adr/ADR-1076-resolve-saved-backend-before-direct-mcp-startup-imports.md (new), wiki/adr/cortex/1076-resolve-saved-backend-before-direct-mcp-startup-imports.md (new), wiki/manifest.json (+4), mcp_server/__main__.py (+1 comment line). All the code and tests I reviewed at db22b16 are unchanged (confirmed with git diff db22b167 fe453171 -- mcp_server/__main__.py tests_py/ outside the comment line below).

The blocking finding: ADR number collision, confirmed independently

I re-derived this myself before reading the coordinator's note, then cross-checked: it holds.

PR #599 (feat/prediction-records, currently at ebe8a6b) already allocates ADR-1076 (a prediction is written, open and resolved against evidence the caller supplies) and ADR-1077 (the advertised tool count is read from the registries), cited in 14 files including production source comments (mcp_server/tool_registry_predictions.py, mcp_server/tool_surface.py, mcp_server/core/calibration.py, mcp_server/infrastructure/prediction_store.py, mcp_server/infrastructure/sqlite_schema_predictions.py, mcp_server/handlers/predict.py, mcp_server/handlers/resolve_prediction.py, mcp_server/handlers/calibration.py, plus tests, CHANGELOG.md, and docs/mcp-tools.md).

PR #600 at fe45317 also allocates ADR-1076, for an unrelated decision (backend resolution). Its own footprint is 3 files, all documentation-layer: wiki/manifest.json, wiki/adr/cortex/1076-resolve-saved-backend-before-direct-mcp-startup-imports.md, docs/adr/ADR-1076-resolve-saved-backend-before-direct-mcp-startup-imports.md. mcp_server/__main__.py itself cites ADR-0505, not ADR-1076, so the new number is not yet load-bearing in this PR's own source.

Root cause matches the coordinator's diagnosis: both branches were cut when main topped out at ADR-1075, and wiki_adr's allocator reads the checkout's own wiki/manifest.json, which cannot see an unmerged sibling branch's allocation. This is not a hypothetical: I enumerated both trees directly (grep -rln "ADR-1076" in each worktree) rather than trusting either PR's description.

I agree renumbering PR #600's ADR to 1078 is the right resolution and the right direction. Renumbering the 3-file, doc-only footprint here is strictly cheaper and lower-risk than renumbering PR #599's 14-file footprint, which includes # source: ADR-1076 / ADR-1077 style comments embedded in production code, handler logic, and schema modules, changes that would need careful re-verification (the craftsmanship gate checks # source: on every constant) rather than a mechanical rename. It also avoids touching a PR with a much larger surface area for a problem this PR's own allocation caused (#600 branched and merged its ADR content after #599 had already claimed the number in its own branch history, even though both are unmerged against main).

I checked whether anything else in either tree currently assumes ADR-1076 means one decision or the other: nothing does. main still tops out at ADR-1075 (confirmed: wiki/manifest.json on origin/main has no ADR-1076 key), so no merged code, doc, or index currently binds the number either way. The collision is real but entirely contained to the two open branches; there is no third place carrying a stale assumption to clean up.

This is what drives the verdict to REQUEST_CHANGES. Everything else about this head is sound (below), but merging PR #600 as-is, in either order relative to #599, corrupts the shared ADR index: wiki_adr's per-repo wiki/manifest.json can only hold one ADR-1076 entry, so whichever PR merges second will either fail wiki_reindex/mirror-parity checks or silently overwrite the first PR's manifest entry, permanently misattributing that ADR number's wiki page section to the wrong decision. That is a demonstrated defect (the collision is enumerated above, not inferred), not a style nit, so it meets the bar for REQUEST_CHANGES rather than a non-blocking comment.

Items 1 to 5, checked as asked

ADR content accuracy. Read docs/adr/ADR-1076-resolve-saved-backend-before-direct-mcp-startup-imports.md end to end against the code. It states the precedence chain correctly (explicit CORTEX_MEMORY_STORE_BACKEND, then CORTEX_BACKEND alias, then non-empty DATABASE_URL/CORTEX_MEMORY_DATABASE_URL, then saved methodology/backend.json, else existing auto behavior), matching backend_marker.py:65-82 which I re-read this round. It states the import-time ordering rationale accurately ("Settings-dependent registry imports bind configuration early, so resolution inside main() would happen too late"), consistent with the actual import order in mcp_server/__main__.py. On the E402 point specifically: the ADR says "the intervening resolver call makes fourteen pre-existing downstream imports trigger E402, as independently measured in the PR review." I re-measured this on the new head by stripping both noqa comment lines and running ruff check --select E402 --no-cache: still exactly 14 errors, unchanged from my prior measurement at db22b16. The wording is accurate, not rounded or exaggerated. The Consequences section is carefully scoped ("not installed-host hook parity, semantic retrieval quality, or PostgreSQL handoff") and does not claim anything beyond what the tests in this PR cover; it even cites my prior review comment and the specific test file as evidence rather than asserting untested behavior. I found no overclaim.

CHANGELOG entry. Under ### Fixed, consistent with the heading used for the adjacent, structurally similar entry for #596. It names the symptom, not the patch: "A saved SQLite selection was honoured by the Claude launcher while direct console/module startup could select a reachable PostgreSQL server, sending the two hosts to different stores," then states the fix and explicitly notes "Existing databases are not migrated or merged." Good.

Mirror parity and manifest. scripts/check_project_wiki.py passed clean on this head ("Project wiki mirrors match their canonical sources"). Diffed docs/adr/ADR-1076-...md against wiki/adr/cortex/1076-...md directly: content matches (only the canonical-source header line differs, which is the expected mirror-generation boilerplate). The wiki/manifest.json entry ("ADR-1076": {"mirror": "ADR-1076-...md", "path": "adr/cortex/1076-...md"}) is structurally identical in shape to the adjacent ADR-1075 entry. Well-formed, contingent entirely on the number itself being wrong (see above).

Gates and full suite, re-run on fe45317. ruff check .: all checks passed. ruff format --check .: 1472 files formatted. scripts/check_craftsmanship.py --base origin/main: OK. scripts/check_doc_claims.py: OK (same one pre-existing exemption). scripts/check_project_wiki.py: mirrors match. pyright: 0 errors/warnings/informations. Full suite (uv run pytest -q, 416.72s): 8670 passed, 91 skipped, 0 failed, 459 subtests passed, identical pass count to the db22b16 run. The three new/PR-specific test modules re-run directly: 12 passed. No orphan processes after any run; ~/.claude/methodology/backend.json mtime unchanged before/after.

The new __main__.py line. Purely a comment, confirmed by diff: git diff db22b167 fe453171 -- mcp_server/__main__.py shows exactly one added line, # File-wide: the resolver call requires the same exemption for 14 existing imports., immediately after the existing # ruff: noqa: E402 line. No code, no behavior change. Re-ran the E402 measurement (above) to confirm the "14" it repeats is still correct on this head, not stale copy-paste from the ADR.

Findings

Blocking

Non-blocking

  • None new this round. The two non-blocking items from the db22b16 review (file-wide noqa precedent, ADR/CHANGELOG convention) are both resolved on this head: the noqa now carries an explanation line, and the ADR/CHANGELOG entries exist (pending the renumber above).

Commands run (this round)

git worktree add .claude/worktrees/review-600-v2 fe453171
git diff db22b167 fe453171 --stat
git diff db22b167 fe453171 -- mcp_server/__main__.py
uv sync --no-default-groups --extra dev --extra postgresql --extra sqlite --extra codebase --extra otel --group typecheck
UV_NO_SYNC=1 uv run ruff check .
UV_NO_SYNC=1 uv run ruff format --check .
UV_NO_SYNC=1 uv run python scripts/check_craftsmanship.py --base origin/main
UV_NO_SYNC=1 uv run python scripts/check_doc_claims.py
UV_NO_SYNC=1 uv run python scripts/check_project_wiki.py
UV_NO_SYNC=1 uv run pyright
UV_NO_SYNC=1 CORTEX_MEMORY_STORE_BACKEND=sqlite uv run pytest -q           # full suite: 8670 passed, 91 skipped
UV_NO_SYNC=1 CORTEX_MEMORY_STORE_BACKEND=sqlite uv run pytest -q tests_py/test_shared_backend_bootstrap.py tests_py/test_shared_host_decisions.py tests_py/infrastructure/test_shared_host_store.py -v  # 12 passed
UV_NO_SYNC=1 uv run ruff check --select E402 --no-cache <copy of __main__.py with both noqa lines stripped>  # 14 errors, unchanged from db22b167 measurement
git fetch origin pull/599/head ; git worktree add /tmp/pr599-check FETCH_HEAD ; grep -rln "ADR-1076\|ADR-1077" .   # 19 hits across 14+ files, confirming the collision and PR #599's footprint size
grep -rln "ADR-1076" .   # (in PR #600's own tree) 3 files, confirming the smaller footprint
diff docs/adr/ADR-1076-*.md wiki/adr/cortex/1076-*.md   # mirror content matches, header boilerplate only difference

Verdict

REQUEST_CHANGES, driven entirely by the ADR number collision (section above), not by code quality. The production code, tests, CHANGELOG entry, and ADR content are all sound and accurately described; the full suite is green (8670/0, matching the prior run); the file-wide noqa now explains itself. I agree with the coordinator's resolution (renumber PR #600's 3-file footprint to 1078 rather than touch PR #599's 14-file footprint), and confirmed nothing else in either open branch or in merged main currently assumes ADR-1076 means one decision or the other, so the fix is a mechanical, low-risk rename with no other cleanup required. Once the renumber lands, this PR should APPROVE on the same evidence presented here.

cdeust added a commit that referenced this pull request Sep 16, 2026
The project's rule puts every worktree at .claude/worktrees/<name>/, which
.gitignore already covers. Codex uses .Codex/worktrees/ instead, and that
path was tracked: reviewing PR #600 found a 60-entry checkout sitting
there, one `git add -A` away from being committed.

Verified with a probe file under .Codex/worktrees/: untracked before,
matched by the rule after (`git check-ignore -v` names .gitignore:66).


Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
@cdeust

cdeust commented Sep 16, 2026

Copy link
Copy Markdown
Owner Author

ZETETIC-REVIEW: APPROVE

Re-verified at head 4a46e2fd (previous verdict REQUEST_CHANGES on fe453171, #600 (comment)). Fresh pass in .claude/worktrees/review-600-v3, removed after review; nothing edited, committed or pushed (git status --porcelain empty at 4a46e2fd). Scripts outside pytest ran with CORTEX_CLAUDE_DIR pointed at a tempdir.

The single blocking finding from round 2 — the ADR-1076 collision with PR #599 — is resolved. One factual correction to the merge-interaction prediction is below; it is not blocking.

1. The renumber is complete and consistent

git diff fe453171 4a46e2fd -M is three files, all rename-plus-number:

  • wiki/adr/cortex/1076-...md → wiki/adr/cortex/1078-resolve-saved-backend-before-direct-mcp-startup-imports.md (96% similarity): number: 1076 → 1078 at line 4, # ADR-1076: → # ADR-1078: at line 9.
  • docs/adr/ADR-1076-...md → docs/adr/ADR-1078-resolve-saved-backend-before-direct-mcp-startup-imports.md (92%): the generated header comment at line 1 now reads Generated by Cortex wiki_reindex from wiki/adr/cortex/1078-...md; ADR-1078, plus number: at line 6 and the H1 at line 11.
  • wiki/manifest.json:3475-3477: key, mirror and path all moved to 1078.

All three places the round-2 comment named are updated, including the generated header comment and the front-matter field.

Grep for 1076 across the branch (grep -rn "1076" . --exclude-dir=.git --exclude-dir=.venv): no hit refers to this decision. Every remaining hit is unrelated — uv.lock / requirements/*.txt wheel hashes, similarity floats in docs/campaigns/i6d2_review_queue_full_*.json, sha256 fragments in docs/program/issue-514-migration-audit.json, and original line 1076-style line numbers in migration ADRs. ADR-1077 likewise appears nowhere in this branch. The only ADR-1078 occurrences are the canonical page, its mirror and the manifest entry.

On the four files the request asked me to check for citations: none of them cites the new number, and none needs to. mcp_server/__main__.py:20 cites ADR-0505 (the parent decision it extends) and ADR-0093 elsewhere; docs/shared-host-memory.md:8,43,54 cites ADR-0505 / ADR-0056 / ADR-0693; docs/codex-plugin.md:100 names the ADR-root contract without a number; the CHANGELOG.md entry under ## [Unreleased] / ### Fixed references #600 and no ADR. That matches the 3-file footprint measured in round 2 — the renumber had nothing else to reach.

2. Mirror parity and manifest

UV_NO_SYNC=1 uv run python scripts/check_project_wiki.py
→ Project wiki mirrors match their canonical sources.

Direct diff docs/adr/ADR-1078-*.md wiki/adr/cortex/1078-*.md: the only difference is the two-line generated mirror header, as expected. Manifest parses, and the ADR key tail is ['ADR-1070' … 'ADR-1075', 'ADR-1078'] with pages["ADR-1078"] = {"mirror": "ADR-1078-resolve-saved-backend-before-direct-mcp-startup-imports.md", "path": "adr/cortex/1078-resolve-saved-backend-before-direct-mcp-startup-imports.md"}.

3. The diff touches only the renumbering

git diff fe453171 4a46e2fd --stat -- mcp_server/ tests_py/ is empty. No code, no tests changed — the delta is 8 insertions / 8 deletions across the two renamed markdown files and the manifest. I re-measured the one constant the ADR asserts anyway, since it is the only number in the page that is not self-evident: stripping both noqa lines from mcp_server/__main__.py and running ruff check --select E402 --no-cache --isolated still gives Found 14 errors., unchanged from the db22b167 and fe453171 measurements. The ADR's "fourteen pre-existing downstream imports" is accurate at this head, not stale.

4. Merge interaction with PR #599 — the manifest still conflicts, in both orders

I simulated this on a scratch clone against main at 0fc6bd1a, with #599 at ea927622 and #600 at 4a46e2fd. Correcting my own round-2 statement that the conflict "disappears as soon as the numbers differ": it does not.

git merge pr599 ; git merge pr600   → CONFLICT (content): wiki/manifest.json
git merge pr600 ; git merge pr599   → CONFLICT (content): wiki/manifest.json

wiki/manifest.json is the only conflicted path in either order. mcp_server/__main__.py reports Auto-merging and resolves cleanly both ways, as does CHANGELOG.md.

The cause is textual adjacency, not the numbers: both branches insert immediately after the ADR-1075 entry, and the } that closes the last entry is the shared trailing context line, so git sees two competing insertions at one anchor. The keys are disjoint (1076/1077 vs 1078), so the resolution is a plain union — keep both sides, comma-join them. I resolved it that way in both orders and validated:

order resulting key tail numerically sorted check_project_wiki.py
#599 then #600 1073, 1074, 1075, 1076, 1077, 1078 yes mirrors match
#600 then #599 1073, 1074, 1075, 1078, 1076, 1077 no mirrors match

All three ADR keys survive in both orders and nothing is lost either way. Recommended order: merge #599 first, then #600. Resolving the union in that direction leaves the manifest keys already in numeric order; the reverse leaves 1078 sitting ahead of 1076/1077, which still validates (key order is not enforced) but diverges from the allocator's natural sorted output and invites a reordering diff on the next wiki_reindex. That is cosmetic, not correctness — either order is safe, and whoever merges second resolves one hunk by keeping both sides.

5. Gates on 4a46e2fd

  • ruff check . → All checks passed!
  • ruff format --check . → 1472 files already formatted
  • scripts/check_craftsmanship.py --base origin/main → Craftsmanship gate: OK
  • scripts/check_doc_claims.py → doc claims OK (1 declared not-a-claim exemption: CONTRIBUTING.md:36, pre-existing)
  • scripts/check_project_wiki.py → mirrors match
  • pyright → 0 errors, 0 warnings, 0 informations
  • pytest -q (full suite, 575.10s) → 8670 passed, 91 skipped, 459 subtests passed, 0 failed, identical to the db22b167 and fe453171 runs.

Findings

Blocking

None. The round-2 blocker is cleared.

Non-blocking

  • The manifest merge conflict above. It belongs to whoever merges second, not to this branch, and the resolution is mechanical.
  • ADR-1078 is cited nowhere outside its own page, mirror and manifest entry — the code it governs cites ADR-0505, the parent decision. Consistent with the doc-only footprint; noting it only so the number's single binding point is on the record.

Commands run

git worktree add .claude/worktrees/review-600-v3 4a46e2fd
uv sync --no-default-groups --extra dev --extra postgresql --extra sqlite --extra codebase --extra otel --group typecheck
git diff fe453171 4a46e2fd --stat -M ; git diff fe453171 4a46e2fd -M
git diff fe453171 4a46e2fd --stat -- mcp_server/ tests_py/          # empty
grep -rn "1076" . --exclude-dir=.git --exclude-dir=.venv            # no hit refers to this decision
grep -rn "1077" . ; grep -rn "1078" .
diff docs/adr/ADR-1078-*.md wiki/adr/cortex/1078-*.md               # header boilerplate only
UV_NO_SYNC=1 uv run ruff check .
UV_NO_SYNC=1 uv run ruff format --check .
UV_NO_SYNC=1 uv run python scripts/check_craftsmanship.py --base origin/main
UV_NO_SYNC=1 uv run python scripts/check_doc_claims.py
UV_NO_SYNC=1 uv run python scripts/check_project_wiki.py
UV_NO_SYNC=1 uv run python -c "import json; json.load(open('wiki/manifest.json'))"   # key tail + ADR-1078 entry
UV_NO_SYNC=1 uv run pyright
UV_NO_SYNC=1 CORTEX_MEMORY_STORE_BACKEND=sqlite uv run pytest -q     # 8670 passed, 91 skipped
UV_NO_SYNC=1 uv run ruff check --select E402 --no-cache --isolated <__main__.py with both noqa lines stripped>   # Found 14 errors
# merge simulation, scratch clone:
git clone --no-hardlinks <repo> ; git fetch gh pull/599/head:pr599 pull/600/head:pr600 main:ghmain
git checkout -B simA ghmain ; git merge pr599 ; git merge pr600   # CONFLICT wiki/manifest.json only
git checkout -B simB ghmain ; git merge pr600 ; git merge pr599   # CONFLICT wiki/manifest.json only
# union-resolved each, then re-ran check_project_wiki.py and a key-order check on both

Verdict

APPROVE. The renumber to ADR-1078 is complete, consistent and confined to documentation; no code or test changed since fe453171; every gate and the full suite are green at 4a46e2fd. Merge #599 first, then #600, and resolve the one wiki/manifest.json hunk by keeping both sides.

@cdeust

cdeust commented Sep 16, 2026

Copy link
Copy Markdown
Owner Author

Review verdict is APPROVE on 4a46e2f, and the renumbering to ADR-1078 checked out completely. PR #599 has merged first as recommended, main is now dd29c89, and this branch conflicts with it in exactly one file: wiki/manifest.json. The reviewer predicted it and measured it on a scratch clone in both orders.

The cause is textual adjacency, not a key collision. Both branches inserted their entry right after ADR-1075 and share the closing } as trailing context, so git cannot decide the order. The resolution is a plain union: after a rebase onto origin/main, keep both sides and order the keys 1076, 1077, 1078, so the manifest stays numerically sorted and the next wiki_reindex does not produce a reordering diff. mcp_server/__main__.py and CHANGELOG.md merge cleanly.

After the rebase, scripts/check_project_wiki.py must still report that the mirrors match, and python -c "import json; json.load(open('wiki/manifest.json'))" must parse. Push, and the review will be re-run on the new head, since the merge gate here refuses a verdict older than the head commit.

@cdeust
cdeust force-pushed the feat/shared-host-decisions branch from 4a46e2f to 54371ba Compare September 16, 2026 21:54
@cdeust

cdeust commented Sep 16, 2026

Copy link
Copy Markdown
Owner Author

ZETETIC-REVIEW: APPROVE

Scope: independent rebase delta review of Cortex PR #600 at 54371ba, compared with previously approved 4a46e2f. This verdict applies to the rebase delta; merge remains dependent on CI at the final head.

No blocking findings in the reviewed delta.

Evidence independently verified:

  • Final worktree HEAD equals 54371ba and git status --porcelain is empty.
  • git range-diff compares all three PR commits. The implementation commit is patch-identical. The two documentation commits differ only in wiki/manifest.json conflict resolution.
  • Compared aggregate patches from original base 0fc6bd1 and rebased base dd29c89. Both modify the same 11 paths. For all 10 paths other than wiki/manifest.json, zero-context patches are identical after removing Git blob-index and hunk-position metadata. This includes implementation, tests, changelog, host documentation, and both ADR-1078 copies.
  • Parsed manifests with Python json. Final pages equal the entire rebased base pages mapping plus precisely the approved ADR-1078 entry. All other top-level manifest fields equal the rebased base. ADR-1076 remains the prediction decision; ADR-1077 remains the advertised-tool-count decision; ADR-1078 remains the startup-backend decision. All six referenced wiki/mirror files exist.
  • Examined the upstream change to mcp_server/main.py: prediction registry import, schema merge, and registration are retained alongside the unchanged PR startup resolution before registry imports.
  • git diff --check HEAD~3 HEAD passed.

Validation supplied by coordinator, not rerun in this review: 59 targeted tests pass on this exact final tree; Ruff check/format, wiki and craftsmanship checks pass; E402 count remains 14. No duplicate test execution was warranted by the inspected rebase delta. Remote CI status was not independently queried by this reviewer.

No repository mutation, commit, GitHub comment, or merge performed.

@cdeust
cdeust merged commit 9656fc4 into main Sep 17, 2026
28 checks passed
@cdeust
cdeust deleted the feat/shared-host-decisions branch September 17, 2026 06:29
cdeust added a commit that referenced this pull request Sep 17, 2026
Codex was folded into "local stdio hosts" although its plugin starts the
server with --profile lean (ten named tools, no hooks) while a direct
codex mcp add gets the full surface. The table now has a column for each,
says which tools lean lacks (predictions, wiki writes, ingestion), where the
shared backend selection lives (#600), and which worktree directory doctor
checks per host.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH
cdeust added a commit that referenced this pull request Sep 17, 2026
…and Codex (#603)

* docs(readme): predictions and calibration, one store for Claude Code and Codex

The README described what Cortex remembers and never that it can record
what it expected (#597, ADR-1076): a section under "Keep context useful"
shows predict, resolve_prediction and calibration with their real return
shapes and says what the Brier score means against the 0.25 of a constant
0.5 forecast. The host table gains the row, and the Codex paragraph says
the plugin reads the same saved backend selection as the Claude launcher
(#600). The unreleased changelog had two "### Added" headings; one now.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH

* docs(readme): one column per host in the capability table

Codex was folded into "local stdio hosts" although its plugin starts the
server with --profile lean (ten named tools, no hooks) while a direct
codex mcp add gets the full surface. The table now has a column for each,
says which tools lean lacks (predictions, wiki writes, ingestion), where the
shared backend selection lives (#600), and which worktree directory doctor
checks per host.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH

* docs(readme): the calibration band the code can return, and the release hedge for Codex

BAND_EDGES steps by 0.2, so the illustrative reliability row shows
[0.6, 0.8]. The Codex paragraph names CORTEX_BACKEND between the two
variables it already named and says the shared backend selection reaches
the plugin with the release after 4.22.0, since the plugin launches the
published package.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH

* docs(readme): the worktree row states the convention, not a doctor check

The doctor check for worktree locations is PR #602, not merged.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH

* docs(readme): the lean profile's real reason, and each worktree cell sourced to what names it

ADR-0693 records why the Codex plugin starts lean: the full surface is the
largest fixed token cost a session pays, not a startup-time limit. The
worktree row cites docs/agent-guidance.md for the Claude Code directory
only; the Codex directory is observed behaviour that #601 gitignored.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH

---------

Co-authored-by: Claude Fable 5.1 <[email protected]>
@cdeust cdeust mentioned this pull request Sep 17, 2026
cdeust added a commit that referenced this pull request Sep 17, 2026
Promotes the Unreleased section to 4.23.0 and moves the seventeen version
surfaces (pyproject, manifest, plugin and marketplace manifests, Codex and
Gemini manifests, package.json and lock, server.json, badge, uv.lock).
Since 4.22.0: session hooks inject only the session's project and global
memories (#604), one saved backend for Claude Code and Codex (#600),
prediction records and calibration (#597), the wiki draft tools over MCP
(#579), procedural skills on SQLite (#596) with a transcript-fed tool
sequence (#591), the console entry point and Codex event adapter for the
lifecycle hooks (#605, #608), the doctor worktree check (#602), and the
launcher fixes (#573, #575, #582). The marketplace pin for
zetetic-team-subagents moves to its released 2.42.0.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH
cdeust added a commit that referenced this pull request Sep 17, 2026
* release: 4.23.0

Promotes the Unreleased section to 4.23.0 and moves the seventeen version
surfaces (pyproject, manifest, plugin and marketplace manifests, Codex and
Gemini manifests, package.json and lock, server.json, badge, uv.lock).
Since 4.22.0: session hooks inject only the session's project and global
memories (#604), one saved backend for Claude Code and Codex (#600),
prediction records and calibration (#597), the wiki draft tools over MCP
(#579), procedural skills on SQLite (#596) with a transcript-fed tool
sequence (#591), the console entry point and Codex event adapter for the
lifecycle hooks (#605, #608), the doctor worktree check (#602), and the
launcher fixes (#573, #575, #582). The marketplace pin for
zetetic-team-subagents moves to its released 2.42.0.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH

* release: the zetetic-team-subagents pin fetches the 2.42.0 tree it advertises

The review of this cut found version 2.42.0 beside ref v2.41.0 and the
2.41.0 sha; installs would have checked out 77b4f785 under a 2.42.0 label.
ref and sha now name the v2.42.0 tag commit 96454db1, as the earlier
deliveries (#553, #554) moved all three fields together.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH

* docs(changelog): name the consolidation launcher that shipped

The ADR-1082 entry cited a consolidate_launch module the craftsmanship
gate refused; the shipped design relaunches session_lifecycle with
--consolidate <mode>, as ADR-1082 and the code say.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cz7A6goxVzfKL9NT7k4zDH

---------

Co-authored-by: Claude Fable 5.1 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant