Lym308758 346ff7b253
fix(memory): rank capacity eviction per record, not per fact_id (#7454)
* fix(memory): rank capacity eviction per record, not per fact_id

select_facts_for_capacity keyed every score by fact_id, so an imported
batch that repeats an id collapsed into a single dict entry: the last
record's score won, and both the ranking pass and the evicted audit
read that one value for every position. A 0.9-confidence record could
therefore be evicted while its own 0.1-confidence duplicate survived.
The import path keeps caller-supplied ids without checking them for
uniqueness, and any over-cap import lands here.

Score by position instead: a parallel list next to the indexed facts,
so ranking and the audit read each record's own score. The public
``scores`` dict stays keyed by fact_id with last-write-wins
semantics, keeping the DeerMem benchmark contract and the callers
that never read it unchanged.

Red on main: test_confidence_policy_scores_duplicate_fact_ids_per_record
fails with the highest-confidence record evicted; green on this branch.

* fix(utils): keep share-less UNC roots out of the extended-length prefix

extended_length_path prefixed every absolute UNC path with
\\?\UNC\, but Win32 only accepts \\?\UNC\server\share\... — a
share-less root (\\server, \\server\, or a bare \) is not a valid
device path, so every Win32 call handed the prefixed spelling fails.
Only prefix when both the server and the share are present;
otherwise return the ordinary spelling unchanged.

Red on main: the \\server, \\server\, //, and //server cases of
test_windows_extended_spelling assert the forged prefix; green on
this branch.
2026-10-25 13:20:15 +08:00

67 lines
3.0 KiB
Python

"""Portability checks for host-visible path segments."""
from __future__ import annotations
import os
from pathlib import Path
def extended_length_path(path: Path) -> Path:
"""Use Windows' extended namespace for local filesystem access.
Prefix before appending children: even a short root can contain a long
document filename. Normalize ordinary paths before adding the prefix;
extended paths bypass Win32's ordinary path normalization. This is lexical
only: callers must still resolve symlinks and enforce their own confinement.
Existing extended/device namespaces (including named pipes) are returned
unchanged, without normalizing their segments.
POSIX paths are unchanged. Do not use this spelling for Docker mount sources
or persisted relative paths.
"""
if os.name != "nt":
return path
if str(path).startswith(("\\\\?\\", "\\\\.\\")):
return path
absolute = os.path.abspath(path)
if absolute.startswith("\\\\"):
# Win32 only accepts \\?\UNC\server\share\...; a share-less UNC root
# (\\server, \\server\, or a bare \) is not a valid device path, so
# keep its ordinary spelling instead of forging an invalid one.
server, separator, share = absolute[2:].partition("\\")
if server and separator and share:
return Path("\\\\?\\UNC\\" + absolute[2:])
return Path(absolute)
return Path("\\\\?\\" + absolute)
# Windows also treats the ISO-8859-1 superscript digits ¹, ² and ³ as device numbers.
# https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file
# CONIN$ and CONOUT$ open the console input and output buffers, not ordinary files.
# https://learn.microsoft.com/en-us/windows/console/console-handles
_WINDOWS_RESERVED_NAMES = frozenset({"CON", "PRN", "AUX", "NUL", "CONIN$", "CONOUT$"} | {f"COM{i}" for i in "123456789¹²³"} | {f"LPT{i}" for i in "123456789¹²³"})
def windows_incompatible_segment(segment: str) -> str | None:
"""Return a reason when *segment* is unsafe to create as a host path component.
Reserved device names and trailing dots or spaces are rejected on every
platform when a name is created: uploads, new custom-skill support files,
and sandbox writes of a path that is not already stored. Reads, deletes of
an existing support file, and access to a path that already exists on the
host do not use this check. Those names alias devices or are silently
stripped on Windows.
``.`` and ``..`` are ignored here; callers already reject traversal.
Do not reject colons, quotes, or control characters here.
"""
if segment in {"", ".", ".."}:
return None
if segment.endswith((" ", ".")):
return "trailing dot or space"
# Windows ignores ASCII spaces before a device name's extension (NUL .txt).
# Trim only for comparison; ordinary filenames must retain their spaces.
stem = segment.split(".", 1)[0].rstrip(" ")
if stem.upper() in _WINDOWS_RESERVED_NAMES:
return "reserved Windows device name"
return None