fix(core): v0.24.0 live-run defects (project lookup, build_context, wiki, man, search scope, examples) - #1637
Conversation
Startup reconciliation rewrites config keys to permalinks while the database keeps each project's display name, and config was then looked up by that name with an exact dict get. A project named `Gamma-Mixed` (key `gamma-mixed`) failed is_locally_syncable, so the startup index and the watcher skipped it, and get_project_mode treated it as cloud. BasicMemoryConfig.project_entry matches by name or permalink, and get_project_mode, is_locally_syncable and the workspace and routing lookups use it. An unknown name still defaults to cloud mode so cloud-only projects stay reachable, but with no cloud route available the local API now answers, so a typo or a deleted project reports "not found" instead of asking for cloud credentials. Fixes #1624 Fixes #1632 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
man fell back to a project named "manual" for unbundled pages and query mode. A local install has no such project, and routing an unknown name to cloud turned every such call into a cloud-credentials error. When no manual project is reachable (none named, none in config, no factory and no cloud credentials), a page miss is "No manual entry" and query mode says what it needs. Fixes #1628 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
build_context answered a memory:// URL that did not name a permalink with the top fuzzy search hit. Routing makes the path project-qualified (main/Cache Layer Design), and the title and file-path lookups saw that prefixed text, so a title URL could only resolve through fuzzy search and often landed on a neighbour that links to it. A miss returned whatever the search ranked first. The link resolver now runs its exact lookups on the own-project remainder before any fuzzy match, with the fuzzy step extracted so it runs last. build_context resolves with use_search=False: a memory:// URL is an address, and a miss returns no primary result. Fixes #1626 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
…tles The wiki projector defers until every accepted change it replays is materialized. Cloud stamps materialized_at from its materialization job, but the local runtime never called mark_accepted_note_change_materialized, so one API or MCP write left bm wiki partial forever. The local provider now settles the journal row after a write reaches a terminal status other than conflict (a disk edit the user must resolve), and after an inline file delete, matching the cloud rule. Fixes #1625 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
Permalink candidates drop the extension, so notes/foo.txt became notes/foo and matched the same-stem Markdown note before any file-path lookup ran. read_content, cat and read_note returned foo.md's bytes for foo.txt. An identifier with a non-Markdown extension now tries its exact file path first; a miss falls through to the usual order. Fixes #1629 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
Project routing matches names by permalink (#1388), but search scoping compared exact strings. Under BASIC_MEMORY_MCP_PROJECT=ALPHA, a project named alpha was filtered out of the scoped project list, so search_all_projects and projects= saw no projects; projects=["BETA"] was refused as unknown. Both now compare permalinks. Fixes #1630 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
Error guidance, docstrings and tool descriptions still showed legacy
project-first positional calls (read_note("qa", "notes/x") reads a note
named qa from project notes/x), a retired list_projects() tool, and a
search_notes kind= parameter that does not exist. The #1603 audit was a
manual pass with no test behind it.
Every example now names a registered tool and passes everything after its
first argument by keyword. A new test scans the string literals in the
MCP tools, prompts and resources and fails on a positional example, an
unknown keyword, or a retired tool name. The search-notes(3) CLI synopsis
listed --search-type, which bm tool search-notes does not accept.
Fixes #1633
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig
Signed-off-by: phernandez <paul@basicmachines.co>
The module docstring claimed created_by/updated_by cannot be set through note content. That holds only where the runtime supplies an identity and stamps over them; on local runtimes the keys pass through as written, which is the intended behavior (#1634). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
Codex Review SummaryThis 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. |
… fallback The underscore relation test used a relation-shaped URL without the target's project prefix, which resolved only through the fuzzy search removed for #1626. Assert the real relation address resolves and the prefix-less form is a miss. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6d0fe2f631
ℹ️ 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".
…lookup file_path is project-relative, so a project-qualified <project>/components/foo.txt missed the exact lookup and fell through to the extension-less permalink candidates that match foo.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8e84981cad
ℹ️ 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".
…retry Workspace-scoped routes qualify identifiers as <workspace>/<project>/Title. The own-project retry only split the first segment and compared the workspace slug with the project permalink, so it was skipped, and with build_context no longer fuzzy matching, the title returned nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
Startup recovery rebuilds its materialization request from note_content, so it carries no journal position and never settled the accepted row; a note recovered on restart and not written again kept the wiki partial. Recovery now settles the note's journal rows up to the recovered db_version when the write ends in any status but conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c60f65485f
ℹ️ 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".
Resource entities (text, images, PDFs) are indexed with permalink NULL, so a permalink candidate built by dropping .txt could only ever match the same-stem Markdown note. Rather than special-casing an exact file-path probe ahead of the candidates in LinkResolver, the shared candidate builder now keeps a real non-Markdown extension, and the ordinary lookup order reaches the file: exact file path, then the own-project remainder retry, whose prefix match normalizes by permalink (so TEST-PROJECT/... and workspace prefixes work too). The builder is shared, so the bulk link resolver and OKF rendering no longer turn [[notes/foo.txt]] into foo.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d9b91333a3
ℹ️ 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".
resolve_entity, the path API entity reads use, ran one exact pass on the raw identifier and never retried the own-project remainder, so a routed <project>/components/foo.txt (resource, permalink NULL) or <project>/<Title> missed under strict resolution. Both entrypoints now share _resolve_in_current_project: exact lookups, then the remainder, then fuzzy search only for non-strict callers that ask for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 62664938e4
ℹ️ 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".
The bulk resolver declined its parsed-prefix fallback when the prefix named the current project, so [[<project>/assets/a.txt]] (a resource with no permalink) and [[<project>/Title]] stayed unresolved on every reindex. It now runs the same strict lookups on the project-relative remainder, matching LinkResolver. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 08e60d6c7e
ℹ️ 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".
…al fallback A caller that names a workspace asked for cloud explicitly. The unknown project fallback to local ASGI now applies only when no workspace is given, so a cloud request without credentials still fails instead of reading a same-named local project. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 780ba311ba
ℹ️ 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".
LinkResolver and the bulk resolver each grew their own own-project prefix retry, and the bulk one handled only <project>/..., so a workspace route's [[<workspace>/<project>/assets/image.png]] stayed unresolved. utils own_project_remainder now strips <workspace>/<project>/ or <project>/ by permalink, and both resolvers call it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig Signed-off-by: phernandez <paul@basicmachines.co>
|
@codex review |
|
Codex Review: Didn't find any major issues. 🚀 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
Summary
This fixes the release-relevant defects from the v0.24.0 live regression run. There is one commit per issue.
Fixes #1624
Fixes #1632
Fixes #1628
Fixes #1626
Fixes #1625
Fixes #1629
Fixes #1630
Fixes #1633
Commits
fix(core): match config entries by permalink; unknown names route local(#1624, #1632)At startup,
synchronize_projectsrewrites config keys to permalinks, but the database keeps the display name. Code then looked config up by that display name with an exactdict.get:is_locally_syncablemissed, so the startup index and the file watcher skipped a project namedGamma-Mixed.get_project_modemissed and called the project cloud.The fix:
BasicMemoryConfig.project_entry(name)matches a project by its name or its permalink.get_project_mode,is_locally_syncable, the workspace lookup and the MCP routing lookup all go through it.--cloud, the local API answers instead, so the error is "project not found".fix(mcp): keep man on the bundled manual without a manual project(#1628)manfell back to a project namedmanual, which only exists in cloud workspaces. Now:manualproject, or cloud credentials keep the old path.fix(core): resolve memory:// titles exactly and keep misses empty(#1626)I reproduced this on main:
memory://zzq-nonexistentreturned an unrelated note. There were two causes:build_context's fallback called the link resolver withuse_search=Trueand took the top fuzzy hit.main/Cache Layer Design). The title and file-path lookups never stripped that prefix, so a title URL could only resolve through the fuzzy search.The fix:
resolve_linkruns its exact lookups on the own-project remainder before any fuzzy match._search_best_matchand runs last.build_contextresolves withuse_search=False.fix(core): stamp local accepted journal rows once their file work settles(#1625)The wiki projector defers until every accepted change it replays is materialized. Cloud marks journal rows as materialized from its materialization job (
wiki_project_changes.py), but core never calledmark_accepted_note_change_materialized, so a local project with any API write stayedpartialforever. The local provider now marks the row with the same rule cloud uses:conflict, since a conflict means a disk edit the user still has to resolve;fix(core): let an exact non-Markdown file path win over stem permalinks(#1629)notes/foo.txtturned into the permalink candidatenotes/fooand matchedfoo.md. An identifier with a non-Markdown extension now tries its exactfile_pathfirst.fix(mcp): match search project scopes by permalink like routing does(#1630)The case-sensitive check in
_matches_constrained_projectand inprojects=selection now compares permalinks, the way project routing already does (#1388).fix(mcp): make model-facing tool-call examples callable as written(#1633)About 100 examples in tool descriptions, docstrings and error guidance were broken:
read_note("{project}", "{identifier}");list_projects();search_notes(kind=...);--search-typeflag in the search-notes(3) CLI synopsis.The fix:
tests/mcp/test_model_facing_call_examples.pyscans the string literals in the MCP tools, prompts and resources. It fails on a positional example, a keyword the tool doesn't accept, or a retired tool name.docs(core)note_authorshipdocstring now says that local authorship keys are ordinary frontmatter (Small note-tool defects from the v0.24.0 live run #1634, as discussed).Not in this PR
config setshould behave while an env var overrides the same key.Tests
Each fix has a regression test that fails on main:
test_config.py: permalink-keyed entrytest_async_client_modes.pyandtest_unknown_project_routing.py: unknown projecttest_tool_posix.py: mantest_link_resolver.pyandtest_tool_build_context.py: titles and missestest_wiki_after_api_writes.py: wiki after create, edit and deletetest_link_resolver.py:.txtvs.mdtest_search_notes_multi_project.py: case-insensitive scopetest_model_facing_call_examples.py: the examples guardjust fast-checkis clean andjust man-regenreports no drift.🤖 Generated with Claude Code
https://claude.ai/code/session_01BF4TkgAJpVrgwzrhemkdig