Skip to content

fix(dev-api): serve legacy memories for a legacy-cohort vector search (#10203)#10485

Merged
kodjima33 merged 1 commit into
BasedHardware:mainfrom
aryanorastar:fix/10203-dev-vector-legacy-fallback
Jul 25, 2026
Merged

fix(dev-api): serve legacy memories for a legacy-cohort vector search (#10203)#10485
kodjima33 merged 1 commit into
BasedHardware:mainfrom
aryanorastar:fix/10203-dev-vector-legacy-fallback

Conversation

@aryanorastar

@aryanorastar aryanorastar commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

What

Closes #10203.

GET /v1/dev/user/memories/vector/search failed closed with 403 missing_rollout_state for un-enrolled legacy-cohort accounts — even though the sibling read paths already recover for exactly these accounts:

both serve the legacy memories collection when pin_memory_system has 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_vector raised 403 on should_use_legacy_fallback (USE_LEGACY_SAFE) — the one signal that explicitly means serve legacy.

Note on the user's report: the list endpoint (GET /v1/dev/user/memories) is already fixed in code, so a user still seeing 403 there is a deploy-lag symptom (issue possibility #1), not a code path. This PR closes the genuine remaining code gap — the vector endpoint.

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 (search_memories_by_vector) and hydrate the hits (get_memories_by_ids), instead of returning 403:

  • vector-relevance order preserved (iterate the ranked IDs, not hydration order);
  • locked content redacted exactly as the list route does;
  • relevance_score left null (the legacy index doesn't expose scores);
  • record_fallback(... to_mode='legacy_memories', outcome='recovered') marks the recovery;
  • any other deny reason keeps the fail-closed 403.

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_memories reaches 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):

test_dev_api_canonical_grant_ordering.py ......... 9 passed
  incl. 3 new vector cases:
    - missing_rollout_state → legacy fallback (200), vector order preserved
    - USE_LEGACY_SAFE       → legacy fallback (200)
    - other deny reason     → still 403
mutation: revert the fix → the 2 fallback cases fail, the 403 case still passes
144 passed across every vector-referencing unit test

The updated test_developer_routes_only_reach_legacy_after_explicit_legacy_safe_decision tripwire now encodes the new (consistent) contract for both routes.

Failure-Class: none

Review in cubic

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@Git-on-my-level Git-on-my-level left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@kodjima33 kodjima33 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

backend dev-api bug fix (serve legacy-cohort memories, #10203) — approve only (CHANGES_REQUESTED)

@aryanorastar

Copy link
Copy Markdown
Contributor Author

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 (PATCH …/baseline, is_baseline), and zero from this PR's vector/search change — the fix is control-flow only (serve legacy vs 403), the DeveloperMemoryVectorSearchResponse model is untouched.

So app-client-openapi.json is stale on main from #8728, not from here — the OpenAPI Contract job is red on every backend PR, not just this one.

The catch with regenerating it in this PR: that single job also runs the Dart/TS/Swift client --check steps, so going green needs the whole regenerated chain — including Desktop/Sources/Generated/OmiApi.generated.swift, which then trips the desktop-changelog gate. That's exactly why I split it into #10482 (the full spec + client-type regen; #10481 exempts generated Swift from the changelog gate so it can carry the Swift file).

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>
@aryanorastar
aryanorastar force-pushed the fix/10203-dev-vector-legacy-fallback branch from 0dfb555 to 67fbc87 Compare July 25, 2026 03:47
@Git-on-my-level
Git-on-my-level dismissed their stale review July 25, 2026 13:59

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 Git-on-my-level left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@kodjima33 kodjima33 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Legacy-cohort accounts could list but not vector-search memories (#10203); mirrors the existing listing/MCP fallback. Tested.

@kodjima33
kodjima33 merged commit fca146c into BasedHardware:main Jul 25, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-maintainer-review Needs a human maintainer to sign off before merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Regression? GET /v1/dev/user/memories still returns 403 missing_rollout_state for some accounts after #10094

3 participants