fix(*): close the embedding pin's upgrade paths and its reporting - #453
gloryfromca wants to merge 6 commits into
Conversation
gloryfromca
left a comment
There was a problem hiding this comment.
Blocking: the retired endpoint repair must run for configs that have already consumed migration generation 8.
I reviewed the complete github/main...HEAD diff, the config/provider/settings/doctor callers, the history that introduced migration generation 8, the repository rules and runtime vocabulary, backward compatibility, test changes, and the provider/config architecture boundary. One upgrade-path defect is blocking inline.
Verification:
uv run --extra dev pytest tests/test_cli_doctor_commands.py tests/test_config_raven_loader.py tests/test_rpc_settings.py -x: 158 passed.uv run --extra dev pytest tests/test_config_loader.py tests/test_config_update_providers.py tests/test_knowledge_embedding.py tests/test_cli_onboard_commands.py -x: 567 passed.git diff --check, Ruff check/format, source-language, large-file, and commit-message checks passed.- The first default-environment test attempt stopped with four setup errors because the optional
raven_everosworkspace package was absent; rerunning with the repository'sdevextra installed that package and produced the passing results above.
I also traced two narrower candidates and did not make them blockers: provider-name spelling aliases remain a pre-existing corner that this change improves for ordinary raw slugs, and endpoint-address ambiguity requires multiple configured providers sharing one URL. Neither outweighs the concrete v8 upgrade failure.
gloryfromca
left a comment
There was a problem hiding this comment.
No blockers; this can merge as far as I am concerned.
The generation-9 split fixes the only blocking upgrade path from the previous review. I re-read the new delta in the context of the full github/main...HEAD change and covered the migration callers/history, project rules and runtime vocabulary, backward compatibility, test changes, and the provider/config architecture boundary. The added regression exercises the formerly failing v8-stamped state without weakening existing coverage.
Verification:
- Exact v8-stamped reproduction: migrated to
{model, provider}, stamp advanced to 9, and both Raven/base loads succeeded. uv run --extra dev pytest tests/test_config_raven_loader.py tests/test_config_loader.py tests/test_config_update_providers.py tests/test_knowledge_embedding.py tests/test_rpc_settings.py tests/test_cli_doctor_commands.py tests/test_cli_onboard_commands.py -x: 726 passed.git diff --check, Ruff check/format, source-language, large-file, and commit-message checks passed.
The previously reported CI shard signal is a timing-gate-only result with zero test failures in an untouched area, so it does not hold this change. The blocker thread is replied to and resolved.
7f4c317 to
6dd6db7
Compare
gloryfromca
left a comment
There was a problem hiding this comment.
No blockers; this can merge as far as I am concerned.
Reviewed the full github/main...HEAD diff and the new post-rebase commit, including the config/RPC/UI callers, migration and load paths, relevant history, backward compatibility, and the architecture terms in CONTEXT-MAP.md / CONTEXT.md. I also checked the repository rules in AGENTS.md / CLAUDE.md and looked for weakened tests; the added regressions exercise the echoed provider address and the warning returned to the save path.
Verification:
uv run --extra dev pytest tests/test_rpc_settings.py tests/test_config_raven_loader.py tests/test_cli_doctor_commands.py tests/test_config_loader.py tests/test_config_update_providers.py tests/test_knowledge_embedding.py tests/test_cli_onboard_commands.py -x: 730 passed.npm test -- src/features/settings/SettingsPage.test.tsx: 123 passed.npm run type-check,npm run gen:check, andnode --check src/live/120-settings.js: passed.- Ruff check/format,
git diff --check, source-language, large-file, and commit-message checks: passed.
npm ci emitted Vitest's engine warning for the local Node 23.10.0 runtime, but dependency installation and all web checks above completed successfully.
gloryfromca
left a comment
There was a problem hiding this comment.
No blockers; this can merge as far as I am concerned.
The new delta removes a stale instruction to configure the retired EverOS embedding block. KnowledgeManager still obtains its endpoint through Raven's embedding pin, so directing the operator to choose the model and its provider matches the active configuration path.
Reviewed the complete github/main...HEAD diff, the affected callers and history, backward compatibility, test integrity, and the repository and architecture rules in AGENTS.md / CLAUDE.md / CONTEXT-MAP.md / CONTEXT.md. No tests were weakened.
Verification: uv run --extra dev pytest tests/test_knowledge_manager.py tests/test_knowledge_embedding.py -x passed 73 tests. Ruff check/format, git diff --check, and the source-language, large-file, and commit-message checks also passed.
The block used to carry the address and the key itself. `EmbeddingConfig` forbids extras, so a config still holding them does not load at all -- `raven doctor` ends in a traceback rather than in a degraded feature, and so does every other command that reads the extension blocks. A config written by an earlier build of this change is exactly that shape, which is how the acceptance environment found it. The migration takes them now. The address is adopted onto whichever configured provider answers there, which is the same question doctor's own migration asks, so the reverse lookup moves to where the providers live and both callers use it. When nothing answers there, the whole block goes rather than half of it: a model left with no provider is a pin every reader resolves to nothing while every screen reads it as configured, and the dropped address is named in the log so it can be configured again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Raven carries no spec for every vendor LiteLLM can reach, and the pin's provider half was checked against the registry alone. So a pin the wizard had stored and every reader resolved -- `provider: deepinfra`, with its key and address sitting in the config -- came back from the settings page as a provider that does not exist. The endpoint was uneditable on the page that exists to edit it. A section the operator wrote is proof the vendor exists, so it counts alongside the registry. The check still earns its keep: a name nothing holds is a typo, and it is still refused rather than surfacing later as a silent fallback to the conversation's model. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Clearing the pin was a no-op. The picker's inherit option sends both halves empty, and the writer dropped empty values before deciding anything -- so the call returned applied, the file kept the old pair, and the picker snapped back on the next load. Editing the file by hand was the only way to unset it. Both halves empty now removes the block and answers with what it held. Doctor reported a move it had not made. The endpoint only moves when a configured provider answers at the address the retired block named, and the return value was discarded: an operator was told the endpoint had been carried across while it sat exactly where it was, and the next run offered the same fix again. The unmade move stays in the remaining list now, with a line saying why and what to do about it. And the canonical SkillForge entry still called the local extraction pipeline `skillForge.everos` and said it belonged to an embedded copy of the memory backend. It calls no service and needs no plugin, which is why the key was renamed; the glossary now says so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…med v8 Generation 8 is on main, and it shipped the move without this repair. So a config can carry the stamp and the shape that cannot load at the same time: the base loader pops the extension blocks, validates what is left, and stamps 8, while the extension read then fails on the two retired fields. A repair gated on 8 never reaches that install, which is every install of the merged build whose config was written by an earlier one. Its own generation, so those get it. Reproduced on a config stamped 8: before, `raven doctor` ended in a traceback and the file was unchanged; after, the endpoint is adopted onto the provider that answers at its address, or the block goes whole, and the stamp moves to 9. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three defects, all found by driving the real screens rather than the layer underneath them. The sentence was the one English paragraph on a translated screen: it was built by interpolating two model names into a finished string, so the catalogue had nothing to look up. It is a catalogue key with placeholders now, which also gives the settings page a translated warning for free. And the page threw it away. Both save paths awaited the call without taking its answer and toasted a fixed "saved", so the field the server had started returning reached nobody. The memory card's embedding row also carries the standing note the default-models row already had, in the same wording, so the risk is stated before a save as well as after one. Saving that row was refused outright. It renders the resolved address as a defaultValue, so every save carries it back whether or not anyone touched it; changing only the model came back as an error naming a field the reader had not edited. An address equal to what the provider already answers with is this page echoing what it was shown -- the same shape as the redacted key the borrow path already drops. One that differs is an instruction, and is still refused. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ure it It said to set `[embedding]` in the EverOS config -- a file nothing reads for this any more, and a file a deployment without the memory plugin does not have at all. The endpoint is a model and the provider that serves it, so the error says that instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
582a977 to
dcbf0f5
Compare
gloryfromca
left a comment
There was a problem hiding this comment.
No blockers; this can merge as far as I am concerned.
After refreshing github/main, this revision is a rebase-only update: git range-diff marks all six PR commits patch-identical to the previously reviewed revision, with no conflict-resolution changes.
Rechecked the complete diff, affected callers and history, backward compatibility, test integrity, and the repository/architecture rules in AGENTS.md / CLAUDE.md / CONTEXT-MAP.md / CONTEXT.md. The previously settled migration thread remains resolved.
Verification:
- The focused Python suite passed all 772 tests in parallel. That run emitted one
BaseEventLoop.__del__invalid-file-descriptor warning during teardown; the identical suite then passed all 772 tests serially without reproducing the warning. - The settings UI suite passed 123 tests; TypeScript, generated-client consistency, and JavaScript syntax checks passed.
- Ruff check/format,
git diff --check, source-language, large-file, and commit-message checks passed.
|
**Not a blocker -- the pin paths are closed and I could not find one left open. One composition deletes the whole pin where base refused the same call, and says "Saved". Two new, individually reasonable changes compose into a silent delete
shown = host_embedding_section().get("base_url", "")
if shown and clean.get("base_url", "").rstrip("/") == shown.rstrip("/"):
clean.pop("base_url")
if given and not clean:
return _clear_embedding_pin(path)In between, It is silent by construction: And it bypasses the module's own rule.
That guard is reached at Base refuses the same call. On Where I disagree with how reachable this isThe pass described the user as one who "never touched that field", with "the model input left empty". I checked, and that is not the resting state of the form: <input ref={model} type="text" defaultValue={cur.model || ''} ... /> // SettingsPage.tsx:2281
<input ref={base} type="text" defaultValue={cur.base_url || ''} ... /> // SettingsPage.tsx:2295Both inputs are pre-filled. On a Save with nothing touched,
So the real path is: a user who clears the model box and saves. That is a plausible thing to do when you mean change the model, and what you get is the entire pin deleted with a success toast. It is narrower than "an untouched save", which is why I am not holding the merge button -- and it is still worth closing, because the difference between "unset the pin" and "I was about to type a new model" is exactly what a confirmation or a warning exists to distinguish. Letting |
|
No blockers; suggestions only, and they are marked inline. Confirmed. With an existing This changes the standing stance from clean to nonblocking, agreeing with the report's classification. A follow-up should pin this exact composition and either require an explicit clear action or return a warning that says the endpoint was removed, rather than the ordinary Saved toast. Verification: the direct temporary-config reproduction observed the deletion and response above; |
Summary
Five upgrade-path and reporting defects in the embedding pin that #414 landed. Three were named as bounded follow-ups in that PR's final review; two came out of driving the acceptance environment afterwards, and both of those were invisible to the unit suite because every fixture already held the new shape.
The two found by acceptance:
EmbeddingConfigforbids extras, soraven doctorends in a traceback rather than in a degraded feature, and so does every other command that reads the extension blocks. The migration takes those keys now: the address is adopted onto whichever configured provider answers there, and when nothing answers the whole block goes rather than half of it, with the dropped address named in the log. A model left with no provider is a pin every reader resolves to nothing while every screen reads it as configured.The three from review:
skillForge.everosand attributed the local extraction pipeline to an embedded copy of the memory backend.Type
Verification
uv run --all-extras pytest -q-- 23058 passed, 110 skipped, 4 failed; the four are the same pre-existing failures main carries (test_agent_loop_token_budget,test_agents_code_launcher,test_agents_oncall_launcher,test_ppt_engine_image_search), matched by test id against a run on the merge base.uv run ruff check .anduv run ruff format --check .-- clean.make check-commits,make check-source-language,make check-large-files-- clean.Every fix was reproduced before and after against a real config or a real gateway, not only through its test: the unloadable config came from the acceptance home itself and
raven doctorwas run on it before and after; the provider refusal was reproduced over a real WebSocket to a running gateway; clearing and the doctor report were each run end to end.Each new test was checked by removing its fix and confirming it fails.
Wider acceptance on the running product, with the memory plugin and without it: a gateway with no memory plugin installed built a knowledge base whose width (4096) was measured from the live endpoint and answered a query sharing almost no keywords with the source (score 0.728); the real TUI recalled a fact stored in an earlier turn, with the recall payload in the audit artifact as evidence rather than the model's answer.
Relevant tests pass locally
Relevant lint / type checks pass locally
User-facing docs or screenshots are updated when needed
Risk
Two changes widen what is accepted rather than narrowing it: a provider section counts alongside the registry, and a migration edits a block it previously left alone. The migration only runs for a config carrying the retired keys and is stamped, so it runs once; a config already in the current shape is untouched. Rolling back any single commit is safe -- they do not depend on each other.
Related Issues
N/A