From 8f14b86e682f9458f3a383b55a790e03b3ddc685 Mon Sep 17 00:00:00 2001 From: jenstandstad Date: Mon, 20 Apr 2026 16:53:12 +0200 Subject: [PATCH] Fixes on logging --- plugins/festinger/festinger/main.py | 38 +++++++++++++++++++++ plugins/festinger/festinger/recollection.py | 6 +--- plugins/festinger/festinger/urd_writer.py | 9 +++++ 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/plugins/festinger/festinger/main.py b/plugins/festinger/festinger/main.py index 727431d..4ac31a9 100644 --- a/plugins/festinger/festinger/main.py +++ b/plugins/festinger/festinger/main.py @@ -723,6 +723,24 @@ async def conflicts(request: Request) -> dict: return {"conflicts": [format_row(r) for r in rows]} +@app.post("/conflicts/clear") +async def clear_conflicts(request: Request) -> dict: + """ + Delete all pending conflicts from the resolution queue and clear the + in-memory pending set. Resolved/error rows are left untouched. + """ + pool = request.app.state.pool + async with pool.acquire() as conn: + result = await conn.execute( + "DELETE FROM resolution_queue WHERE status = 'pending'" + ) + # result is a string like "DELETE 17" + deleted = int(result.split()[-1]) if result else 0 + cache.pending_conflicts.clear() + log.info("conflicts cleared deleted=%d", deleted) + return {"status": "ok", "deleted": deleted} + + @app.get("/kg-log") async def kg_log(request: Request, limit: int = 100, offset: int = 0, op: str = "") -> dict: """Return recent knowledge graph write log entries, newest first.""" @@ -1491,6 +1509,9 @@ ADMIN_HTML = """

Pending conflicts

+
+ +
Loading…

Knowledge graph write log

@@ -1549,6 +1570,23 @@ ADMIN_HTML = """ el.textContent = text; }} + async function clearConflicts(btn) {{ + if (!confirm('Delete all pending conflicts from the resolution queue?')) return; + btn.disabled = true; + showResult('Clearing pending conflicts…', true); + try {{ + const r = await fetch('/conflicts/clear', {{method: 'POST'}}); + const d = await r.json(); + showResult(JSON.stringify(d, null, 2), r.ok); + await loadStats(); + await loadConflicts(); + }} catch(e) {{ + showResult('Error: ' + e.message, false); + }} finally {{ + btn.disabled = false; + }} + }} + async function runResolution(btn) {{ btn.disabled = true; showResult('Running resolution job…', true); diff --git a/plugins/festinger/festinger/recollection.py b/plugins/festinger/festinger/recollection.py index 0b8a159..2049db4 100644 --- a/plugins/festinger/festinger/recollection.py +++ b/plugins/festinger/festinger/recollection.py @@ -17,11 +17,7 @@ from .cache import SoasRow, UrdEdge log = logging.getLogger("festinger.recollection") -ZERO_HIT_TEMPLATE = ( - "? {concept}: no recollection. If not a typo, store it before proceeding:\n" - " gutask iknowthat '{concept} -isa in context of '\n" - " gutask iknowthat '{concept} -ispart in context of '" -) +ZERO_HIT_TEMPLATE = "? {concept}: no recollection stored yet." # --------------------------------------------------------------------------- diff --git a/plugins/festinger/festinger/urd_writer.py b/plugins/festinger/festinger/urd_writer.py index 6d8cead..67c4129 100644 --- a/plugins/festinger/festinger/urd_writer.py +++ b/plugins/festinger/festinger/urd_writer.py @@ -66,6 +66,15 @@ async def insert_urd_edge( # Fast-path collision detection — in-memory existing = cache.urd_by_concept_dim.get(key) if existing is not None: + if existing.parent_id == req.parent_id: + # Identical re-assertion of an already-stored fact — silent no-op. + # This is normal: the cue scanner re-extracts the same facts from + # conversation history on every round. + log.debug( + "urd skip identical concept=%d parent=%d dim=%d", + req.concept_id, req.parent_id, req.dim_id, + ) + return None collision = CollisionInfo( concept_id=req.concept_id, existing_parent_id=existing.parent_id,