Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/aelfrice/context_rebuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,24 +287,36 @@ def rebuild_v14(
session_ids: set[str] = {b.id for b in session_hits}

# Pack, accounting tokens. L0 always survives.
# Output-level content_hash dedup (#281): different belief_ids can
# share a content_hash (re-ingest before #219, multi-source ingest,
# or any future dedup gap). Without this, the rebuild block can
# surface 10+ identical lines. Locked wins (it's prepended whole);
# subsequent tiers skip any hash already packed.
used: int = sum(_estimate_belief_tokens(b) for b in locked)
out: list[Belief] = list(locked)
seen_hashes: set[str] = {b.content_hash for b in locked}

for b in session_hits:
if b.content_hash in seen_hashes:
continue
cost = _estimate_belief_tokens(b)
if used + cost > token_budget:
break
out.append(b)
used += cost
seen_hashes.add(b.content_hash)

for b in non_locked_hits:
if b.id in session_ids:
continue # already surfaced above
if b.content_hash in seen_hashes:
continue
cost = _estimate_belief_tokens(b)
if used + cost > token_budget:
break
out.append(b)
used += cost
seen_hashes.add(b.content_hash)

return _format_block(
recent_turns, out, session_ids, token_budget=token_budget,
Expand Down
104 changes: 104 additions & 0 deletions tests/test_context_rebuilder_hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,110 @@ def test_ac1_pure_rebuild_v14_orders_locked_then_session_then_l1(
assert a < b


# --- #281: output-level content_hash dedup --------------------------------
#
# Note on test setup: #283 added UNIQUE(content_hash) on beliefs, so two
# rows with the same content_hash can no longer be inserted via the store
# API. The dedup loop in rebuild_v14 is a defense-in-depth safety net for
# (a) legacy stores opened before the consolidation migration runs, and
# (b) the case where retrieve() and list_locked_beliefs() both surface
# the same belief id (different rows for the same logical belief in the
# returned lists). To exercise the dedup branch without violating the
# UNIQUE constraint, we monkeypatch the retrieval seams to inject
# duplicate Belief objects that don't actually live in the store.


def test_issue_281_dedup_collapses_duplicates_in_retrieved_lists(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Same content_hash returned multiple times surfaces once."""
store = MemoryStore(str(tmp_path / "m.db"))
try:
dups = [
Belief(
id=f"dup{i:02d}",
content="graceful degradation: warn and continue",
content_hash="SHARED_HASH",
alpha=1.0, beta=1.0, type=BELIEF_FACTUAL,
lock_level=LOCK_NONE, locked_at=None,
demotion_pressure=0,
created_at="2026-04-26T00:00:00Z",
last_retrieved_at=None,
)
for i in range(10)
]
monkeypatch.setattr(
store, "list_locked_beliefs", lambda: [],
)
monkeypatch.setattr(
"aelfrice.context_rebuilder.retrieve",
lambda *a, **kw: dups,
)
monkeypatch.setattr(
"aelfrice.context_rebuilder._session_scoped_hits",
lambda *a, **kw: [],
)
block = rebuild_v14(
[RecentTurn(role="user", text="graceful degradation")],
store,
)
finally:
store.close()
appearances = sum(
1 for i in range(10) if f'id="dup{i:02d}"' in block
)
assert appearances == 1, (
f"expected 1 surviving dup, got {appearances}"
)


def test_issue_281_locked_takes_precedence_over_dup_l1_hits(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch,
) -> None:
"""When a locked belief shares content_hash with an L1 hit, locked
wins and the L1 hit is skipped (not appended below)."""
store = MemoryStore(str(tmp_path / "m.db"))
try:
locked = Belief(
id="LCK", content="kitchen has bananas",
content_hash="H1",
alpha=1.0, beta=1.0, type=BELIEF_FACTUAL,
lock_level=LOCK_USER,
locked_at="2026-04-26T00:00:00Z",
demotion_pressure=0,
created_at="2026-04-26T00:00:00Z",
last_retrieved_at=None,
)
l1_dup = Belief(
id="L1A", content="kitchen has bananas",
content_hash="H1",
alpha=1.0, beta=1.0, type=BELIEF_FACTUAL,
lock_level=LOCK_NONE, locked_at=None,
demotion_pressure=0,
created_at="2026-04-26T00:00:00Z",
last_retrieved_at=None,
)
monkeypatch.setattr(
store, "list_locked_beliefs", lambda: [locked],
)
monkeypatch.setattr(
"aelfrice.context_rebuilder.retrieve",
lambda *a, **kw: [locked, l1_dup],
)
monkeypatch.setattr(
"aelfrice.context_rebuilder._session_scoped_hits",
lambda *a, **kw: [],
)
block = rebuild_v14(
[RecentTurn(role="user", text="kitchen contents")],
store,
)
finally:
store.close()
assert 'id="LCK"' in block
assert 'id="L1A"' not in block


# --- AC2: empty transcript / missing store --------------------------------


Expand Down
Loading