Skip to content

Commit 392422c

Browse files
authored
Summarize scope demotions in memory health (#74)
1 parent 97dbfba commit 392422c

5 files changed

Lines changed: 111 additions & 1 deletion

File tree

docs/REPORT-memory-operating-layer-eval.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,31 @@ uv run --extra sqlite python eval/scripts/memory_operating_poc.py \
336336
- ranking diagnostics는 positive boost와 negative demotion을 분리해서 기록한다.
337337
- 최종 result order는 조정된 resonance 기준으로 정렬된다.
338338

339+
후속 health demotion summary guard 검증:
340+
341+
```bash
342+
uv run --extra sqlite python eval/scripts/memory_operating_poc.py \
343+
--results ~/synaptic-eval/memory_operating_health_demotion_summary_results.json
344+
```
345+
346+
결과:
347+
348+
| 항목 ||
349+
|---|---:|
350+
| result | PASS |
351+
| gates | `31/31` |
352+
| health_summarizes_scope_demotions | `true` |
353+
| memory_demoted_retrieval_count | `1` |
354+
| memory_demoted_node_count | `1` |
355+
| max_memory_scope_demotion | `0.1` |
356+
| memory_adjusted_retrieval_count | `2` |
357+
| memory_adjusted_node_count | `2` |
358+
359+
추가로 검증된 동작:
360+
361+
- retrieval ledger에 기록된 scope demotion diagnostics가 `memory_health()` summary로 집계된다.
362+
- positive boost, negative demotion, 전체 adjustment count를 health report에서 분리해서 볼 수 있다.
363+
339364
### 4. OpenIE off baseline smoke
340365

341366
```bash

eval/scripts/memory_operating_poc.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ async def run_memory_operating_poc(args: argparse.Namespace) -> dict[str, Any]:
511511
item for item in edge_only_penalty_result.nodes if item.node.id == edge_only_suspect.id
512512
)
513513
await graph._record_retrieval_event(edge_boost_result, scope=scope)
514+
await graph._record_retrieval_event(negative_scope_result, scope=scope)
514515
await graph._record_retrieval_event(edge_only_penalty_result, scope=scope)
515516
for i in range(12):
516517
await backend.save_memory_score(
@@ -632,12 +633,23 @@ async def run_memory_operating_poc(args: argparse.Namespace) -> dict[str, Any]:
632633
),
633634
"health_summarizes_memory_ranking_diagnostics": (
634635
ranking_health.memory_boosted_retrieval_count >= 1
636+
and ranking_health.memory_demoted_retrieval_count >= 1
637+
and ranking_health.memory_adjusted_retrieval_count >= 2
635638
and ranking_health.memory_penalized_retrieval_count >= 1
636639
and ranking_health.memory_boosted_node_count >= 1
640+
and ranking_health.memory_demoted_node_count >= 1
641+
and ranking_health.memory_adjusted_node_count >= 2
637642
and ranking_health.memory_penalized_node_count >= 1
638643
and ranking_health.max_memory_scope_boost > 0.0
644+
and ranking_health.max_memory_scope_demotion > 0.0
645+
and ranking_health.max_memory_scope_adjustment > 0.0
639646
and ranking_health.max_memory_signal_penalty > 0.0
640647
),
648+
"health_summarizes_scope_demotions": (
649+
ranking_health.memory_demoted_retrieval_count >= 1
650+
and ranking_health.memory_demoted_node_count >= 1
651+
and ranking_health.max_memory_scope_demotion > 0.0
652+
),
641653
"health_reports_top_reinforced_edges": (
642654
"poc_edge_score_boost_relation" in ranking_health.top_reinforced_edge_ids
643655
),

src/synaptic/graph.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2853,6 +2853,8 @@ async def _apply_scope_boost(self, result: SearchResult, scope: MemoryScope) ->
28532853
adjusted_nodes = 0
28542854
clamped_nodes = 0
28552855
max_abs_boost = 0.0
2856+
max_positive_boost = 0.0
2857+
max_demotion = 0.0
28562858
for idx, item in enumerate(result.nodes):
28572859
raw = (
28582860
local_by_node.get(item.node.id, 0.0)
@@ -2866,8 +2868,10 @@ async def _apply_scope_boost(self, result: SearchResult, scope: MemoryScope) ->
28662868
max_abs_boost = max(max_abs_boost, abs(boost))
28672869
if boost > 0.0:
28682870
boosted_nodes += 1
2871+
max_positive_boost = max(max_positive_boost, boost)
28692872
else:
28702873
demoted_nodes += 1
2874+
max_demotion = max(max_demotion, abs(boost))
28712875
item.activation = max(0.0, item.activation * (1.0 + boost))
28722876
item.resonance = max(0.0, item.resonance * (1.0 + boost))
28732877
if boost > 0.0 and idx > 0 and item.resonance > base_resonances[idx - 1]:
@@ -2883,6 +2887,8 @@ async def _apply_scope_boost(self, result: SearchResult, scope: MemoryScope) ->
28832887
)
28842888
result.diagnostics["memory_scope_edge_score_hits"] = float(len(edge_by_node))
28852889
result.diagnostics["memory_scope_max_abs_boost"] = max_abs_boost
2890+
result.diagnostics["memory_scope_max_positive_boost"] = max_positive_boost
2891+
result.diagnostics["memory_scope_max_demotion"] = max_demotion
28862892
result.diagnostics["memory_scope_order_clamps"] = float(clamped_nodes)
28872893

28882894
async def _apply_memory_signal_penalties(
@@ -3282,20 +3288,54 @@ async def memory_health(
32823288
if edge.id.startswith("openie_") or _prop_bool(edge.properties, "is_openie")
32833289
)
32843290
boosted_retrieval_count = 0
3291+
demoted_retrieval_count = 0
3292+
adjusted_retrieval_count = 0
32853293
penalized_retrieval_count = 0
32863294
boosted_node_count = 0
3295+
demoted_node_count = 0
3296+
adjusted_node_count = 0
32873297
penalized_node_count = 0
32883298
max_scope_boost = 0.0
3299+
max_scope_demotion = 0.0
3300+
max_scope_adjustment = 0.0
32893301
max_signal_penalty = 0.0
32903302
for event in retrieval_events:
32913303
props = event.properties or {}
32923304
boosted_nodes = _prop_int(props, "memory_scope_boosted_nodes", 0)
3305+
demoted_nodes = _prop_int(props, "memory_scope_demoted_nodes", 0)
3306+
adjusted_nodes = _prop_int(
3307+
props,
3308+
"memory_scope_adjusted_nodes",
3309+
boosted_nodes + demoted_nodes,
3310+
)
32933311
penalized_nodes = _prop_int(props, "memory_signal_penalized_nodes", 0)
32943312
if boosted_nodes > 0:
32953313
boosted_retrieval_count += 1
32963314
boosted_node_count += boosted_nodes
32973315
max_scope_boost = max(
32983316
max_scope_boost,
3317+
_prop_float(
3318+
props,
3319+
"memory_scope_max_positive_boost",
3320+
_prop_float(props, "memory_scope_max_abs_boost", 0.0),
3321+
),
3322+
)
3323+
if demoted_nodes > 0:
3324+
demoted_retrieval_count += 1
3325+
demoted_node_count += demoted_nodes
3326+
max_scope_demotion = max(
3327+
max_scope_demotion,
3328+
_prop_float(
3329+
props,
3330+
"memory_scope_max_demotion",
3331+
_prop_float(props, "memory_scope_max_abs_boost", 0.0),
3332+
),
3333+
)
3334+
if adjusted_nodes > 0:
3335+
adjusted_retrieval_count += 1
3336+
adjusted_node_count += adjusted_nodes
3337+
max_scope_adjustment = max(
3338+
max_scope_adjustment,
32993339
_prop_float(props, "memory_scope_max_abs_boost", 0.0),
33003340
)
33013341
if penalized_nodes > 0:
@@ -3327,10 +3367,16 @@ async def memory_health(
33273367
openie_artifact_count=openie_nodes + openie_edges,
33283368
openie_failure_rate=(failures / selected) if selected else 0.0,
33293369
memory_boosted_retrieval_count=boosted_retrieval_count,
3370+
memory_demoted_retrieval_count=demoted_retrieval_count,
3371+
memory_adjusted_retrieval_count=adjusted_retrieval_count,
33303372
memory_penalized_retrieval_count=penalized_retrieval_count,
33313373
memory_boosted_node_count=boosted_node_count,
3374+
memory_demoted_node_count=demoted_node_count,
3375+
memory_adjusted_node_count=adjusted_node_count,
33323376
memory_penalized_node_count=penalized_node_count,
33333377
max_memory_scope_boost=max_scope_boost,
3378+
max_memory_scope_demotion=max_scope_demotion,
3379+
max_memory_scope_adjustment=max_scope_adjustment,
33343380
max_memory_signal_penalty=max_signal_penalty,
33353381
top_reinforced_node_ids=[score.node_id for score in top_node_scores if score.node_id],
33363382
top_reinforced_edge_ids=[score.edge_id for score in top_edge_scores if score.edge_id],

src/synaptic/models.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,16 @@ class MemoryHealthReport:
261261
openie_artifact_count: int = 0
262262
openie_failure_rate: float = 0.0
263263
memory_boosted_retrieval_count: int = 0
264+
memory_demoted_retrieval_count: int = 0
265+
memory_adjusted_retrieval_count: int = 0
264266
memory_penalized_retrieval_count: int = 0
265267
memory_boosted_node_count: int = 0
268+
memory_demoted_node_count: int = 0
269+
memory_adjusted_node_count: int = 0
266270
memory_penalized_node_count: int = 0
267271
max_memory_scope_boost: float = 0.0
272+
max_memory_scope_demotion: float = 0.0
273+
max_memory_scope_adjustment: float = 0.0
268274
max_memory_signal_penalty: float = 0.0
269275
top_reinforced_node_ids: list[str] = field(default_factory=_str_list)
270276
top_reinforced_edge_ids: list[str] = field(default_factory=_str_list)

tests/test_memory_operating_layer.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1265,7 +1265,22 @@ async def test_memory_health_summarizes_retrieval_ranking_diagnostics():
12651265
scope=scope,
12661266
properties={
12671267
"memory_scope_boosted_nodes": "2.000000",
1268+
"memory_scope_adjusted_nodes": "2.000000",
12681269
"memory_scope_max_abs_boost": "0.100000",
1270+
"memory_scope_max_positive_boost": "0.100000",
1271+
},
1272+
)
1273+
)
1274+
await backend.save_retrieval_event(
1275+
RetrievalEvent(
1276+
id="ret_demotion",
1277+
query="demotion",
1278+
scope=scope,
1279+
properties={
1280+
"memory_scope_demoted_nodes": "2.000000",
1281+
"memory_scope_adjusted_nodes": "2.000000",
1282+
"memory_scope_max_abs_boost": "0.080000",
1283+
"memory_scope_max_demotion": "0.080000",
12691284
},
12701285
)
12711286
)
@@ -1299,12 +1314,18 @@ async def test_memory_health_summarizes_retrieval_ranking_diagnostics():
12991314

13001315
health = await graph.memory_health(scope=scope, persist_signals=False)
13011316

1302-
assert health.retrieval_events == 2
1317+
assert health.retrieval_events == 3
13031318
assert health.memory_boosted_retrieval_count == 1
1319+
assert health.memory_demoted_retrieval_count == 1
1320+
assert health.memory_adjusted_retrieval_count == 2
13041321
assert health.memory_penalized_retrieval_count == 1
13051322
assert health.memory_boosted_node_count == 2
1323+
assert health.memory_demoted_node_count == 2
1324+
assert health.memory_adjusted_node_count == 4
13061325
assert health.memory_penalized_node_count == 1
13071326
assert health.max_memory_scope_boost == pytest.approx(0.10)
1327+
assert health.max_memory_scope_demotion == pytest.approx(0.08)
1328+
assert health.max_memory_scope_adjustment == pytest.approx(0.10)
13081329
assert health.max_memory_signal_penalty == pytest.approx(0.05)
13091330
assert len(health.top_reinforced_node_ids) == 10
13101331
assert health.top_reinforced_edge_ids == ["edge_top"]

0 commit comments

Comments
 (0)