fix(dev-api): serve legacy memories for a legacy-cohort vector search (#10203)#10485
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Git-on-my-level
left a comment
There was a problem hiding this comment.
Thanks for the focused fix here — the fallback is narrow, keeps other deny reasons fail-closed, preserves legacy vector ordering, and the added unit coverage targets the right regression cases.
I’m requesting changes for one concrete merge blocker: the Public Developer API contract check is failing because docs/api-reference/app-client-openapi.json is stale after this Developer API route change. Please regenerate and commit the app-client OpenAPI contract (backend/scripts/export_openapi.py --write ../docs/api-reference/app-client-openapi.json, or the repo’s equivalent wrapper) so CI is green.
Given this touches Developer API memory reads/vector search over user memories and legacy rollout fallback behavior, I’d still want a human maintainer to sanity-check the rollout/data-handling semantics before merge, but I don’t see a security/supply-chain issue in the diff itself.
by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with need human response.
|
Thanks — but this diff doesn't change the app-client contract. I regenerated it on this branch to check: the result is +104 lines that are entirely the memories baseline route/field from #8728 ( So The catch with regenerating it in this PR: that single job also runs the Dart/TS/Swift client Once #10482 lands, this goes green with no change. Since @kodjima33 has already approved the substance, could we either merge #10482 first, or treat this OpenAPI-contract failure as the pre-existing #8728 drift it is? Happy to rebase after #10482 to confirm green. |
…BasedHardware#10203) GET /v1/dev/user/memories/vector/search failed closed with 403 missing_rollout_state for un-enrolled legacy-cohort accounts, while the sibling read paths recover: the memory list (BasedHardware#9892/BasedHardware#10094) and MCP (BasedHardware#10095) already serve the legacy `memories` collection for exactly these accounts. So an affected account could list its memories but not vector-search them — the remaining "another rollout-state path still failing closed" cohort BasedHardware#10203 asks about. (GET /v1/dev/user/memories itself is already fixed, so a user still hitting 403 on the list endpoint is a deploy-lag symptom, not this code path.) search_memories_vector even raised 403 on `should_use_legacy_fallback` (USE_LEGACY_SAFE) — the one signal that explicitly means "serve legacy." Fix: on a legacy-cohort signal (USE_LEGACY_SAFE, or a deny whose only reason is missing_rollout_state), search the legacy `memories` vector index and hydrate results, preserving vector-relevance order and redacting locked content exactly as the list route does. record_fallback marks the recovery. Any other deny reason keeps the fail-closed 403. This is the 4th instance of the same cause (a default-read surface failing closed for an un-enrolled legacy account instead of serving legacy). The enforceable guard landed here is the updated source tripwire asserting the vector route recovers on the shared signal; unifying all read surfaces behind one predicate ripples into the list route's fallthrough + its tripwire, so it is tracked as a follow-up rather than widened into this fix. Verify (.venv, python3.11): - test_dev_api_canonical_grant_ordering.py 9 passed, incl. 3 new vector cases (legacy fallback on missing_rollout_state + USE_LEGACY_SAFE, and other-deny-reason still 403); reverting the fix fails the 2 fallback cases and keeps the 403 case (mutation-checked). - 144 passed across every vector-referencing unit test. Failure-Class: none Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
0dfb555 to
67fbc87
Compare
OpenAPI/Public Developer API contract blocker from this automation review is resolved on current head 67fbc87; checks now pass. Human maintainer review label remains.
Git-on-my-level
left a comment
There was a problem hiding this comment.
Thanks for the follow-up here. I re-checked the current head and the previous generated-contract blocker is no longer blocking: the Public Developer API contract and backend checks are passing now, so I dismissed my stale automation change-request review.
Implementation-wise this still looks like a narrow bug fix: auth/default-memory grant checks remain ahead of the memory-system branch, legacy serving is limited to USE_LEGACY_SAFE or the missing_rollout_state legacy-cohort case, other deny reasons still fail closed, and the tests cover vector-order preservation plus both fallback and deny paths.
Because this touches Developer API vector search over user memories and legacy rollout fallback semantics, I’m leaving this as a positive signal rather than a formal approval; the existing human maintainer review label is still appropriate before merge.
by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with need human response.
What
Closes #10203.
GET /v1/dev/user/memories/vector/searchfailed closed with403 missing_rollout_statefor un-enrolled legacy-cohort accounts — even though the sibling read paths already recover for exactly these accounts:GET /v1/dev/user/memories(Developer API: GET /v1/dev/user/memories returns 403 missing_rollout_state (conversations/action-items OK) #9892 / fix(dev): serve legacy memories when a legacy-cohort account has no rollout state #10094), andboth serve the legacy
memoriescollection whenpin_memory_systemhas resolved the account to LEGACY and the only signal is an absent rollout doc. So an affected account could list its memories but not vector-search them — the "another rollout-state path still failing closed" cohort the issue asks about (possibility #3).Worse,
search_memories_vectorraised 403 onshould_use_legacy_fallback(USE_LEGACY_SAFE) — the one signal that explicitly means serve legacy.Fix
On a legacy-cohort signal —
USE_LEGACY_SAFE, or a deny whose only reason ismissing_rollout_state— search the legacymemoriesvector index (search_memories_by_vector) and hydrate the hits (get_memories_by_ids), instead of returning 403:relevance_scoreleftnull(the legacy index doesn't expose scores);record_fallback(... to_mode='legacy_memories', outcome='recovered')marks the recovery;Why not a shared predicate (yet)
This is the 4th instance of one cause — a default-read surface failing closed for an un-enrolled legacy account instead of serving legacy (#9892 → #10094 list, #10095 MCP, this = vector). The ideal class-level guard is one predicate every read surface calls. But
get_memoriesreaches legacy by fallthrough while the vector route returns explicitly, so unifying them ripples into the list route's control flow and its static tripwire. Per AGENTS.md ("land the enforceable guard now, track high-blast-radius follow-up explicitly") I land the focused fix plus the updated tripwire (which now asserts the vector route recovers on the shared signal) and flag the shared-predicate extraction as a follow-up.Verification
Ran with a real backend venv (Python 3.11):
The updated
test_developer_routes_only_reach_legacy_after_explicit_legacy_safe_decisiontripwire now encodes the new (consistent) contract for both routes.Failure-Class: none