mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-11-12 22:20:33 +00:00
* fix(memory): reject duplicate fact ids in imports regardless of entry order A backup containing two entries for the same fact id was accepted or rejected depending only on their order. The duplicate check in _commit_changes_locked consulted the map of prepared writes, but an entry whose normalized content matches the stored fact is skipped from that map - so an unchanged entry followed by an edited duplicate passed the check while the reverse order raised, and the saved snapshot ended up with whichever entry came last. Track every incoming id in a seen-set for duplicate detection, before the unchanged-entry skip. The saved snapshot now survives the rejection in both orders. Fixes #8150 * fix(memory): validate duplicate import ids before capacity selection Copilot review follow-up on #8153: the storage-level duplicate guard runs after _select_for_capacity, and the capacity policy can drop one of two same-id entries (e.g. lower-confidence copies trimmed to max_facts) - the duplicate then never reaches the guard and the import outcome still depends on entry order. Validate all normalized incoming ids in import_memory_data before capacity selection. The storage-level guard stays as defense in depth. Regression test with max_facts=10 and 9 distinct high-confidence facts plus two same-id copies. * fix(memory): surface duplicate fact id errors with their own detail willem-bd review on #8153, three follow-ups: 1. P2: the bare ValueError fell through to the router's generic catch, so POST /api/memory/import answered with the facts-array message even when every fact had non-empty content. Add MemoryDuplicateFactIdError (same type as #8151) at the manager boundary and map it to its own 400 detail that names the duplicated id; router test asserts the exact detail. 2. P3: the duplicate check lived inside the apply_changes-override branch, so the base MemoryStorage save() path bypassed both guards. Move it before the branch split, right after normalize_memory_data, matching #8151's validate-before-capacity posture. 3. P3: parametrize the order-dependence regression over the default bucket (agent_name=None) and "researcher", and assert the seeded snapshot survives the rejection in both orders. * test(memory): pin the storage duplicate guard and fix the no-op assertion willem-bd review follow-ups on #8153: 1. The snapshot-survival assertion compared storage.load against get_memory_data, which is itself storage.load - both reads happened after the rejected import, so a regression that partially applied the duplicate would pass. Capture the seeded snapshot before the rejected import and compare against it. 2. The updater gate rejects import duplicates before storage is touched, so nothing exercised the storage-level guard in _commit_changes_locked with an unchanged duplicate first - reverting it would keep the suite green. Add a direct apply_changes regression test; verified it fails with the guard removed. * style(memory): apply ruff fixes after #8151 merge resolution * test(memory): assert untouched store in the storage-guard pin; facade import willem-bd review follow-ups on #8153: 1. The storage-guard regression test pinned rejection but not the untouched-store half: capture the seeded snapshot right after seeding and assert storage.load still equals it after the rejection, so a regression that partially applies the first entry before raising fails. 2. The router regression test imported MemoryDuplicateFactIdError from the manager module directly; use the package-facade import consistent with the other manager-error usage (the symbol is already re-exported from deerflow.agents.memory since #8151). * test(memory): drop the mock router duplicate-id test ShenAC-SAC review on #8153: #8151 already drives the real import route with duplicate IDs and asserts the same 400 response plus an unchanged snapshot, and the mock test's docstring implied a detail the assertion did not check. The direct apply_changes() regression is kept. Also removes the blank line after the docstring that tripped ruff format --check on the repo-pinned Ruff version. * test(memory): remove the orphaned mock-router test body ShenAC-SAC review: my earlier deletion removed the function definition and docstring but left the test body running inside test_clear_route_keeps_working_for_windows_reserved_agent_name. Remove the whole block and the now-unused MemoryDuplicateFactIdError import; #8151 already covers the duplicate-ID response through the real import route.