Skip to content

KG ephemeral sweep reports 0 for 52 days while 178–271 pure-ID nodes escape a live guard — sweep shares the guard's blind spot by construction (#153 phase-2) #970

Description

@olegbrok

Summary

The daily ephemeral sweep has reported n_candidates=0 for 52 consecutive days (2026-06-10 → 2026-08-01). That zero is being used as the regrowth instrument for deciding how urgent the write-path guard is (#153 phase-2).

The zero is real for the patterns the detector knows, and misleading as a measure of regrowth. In the same graph, 286 pure-identifier entities carrying ~557 edges are present that is_ephemeral does not match — and 281 of them were created after the guard shipped (2026-06-07, 6336d8a / #660). One was created today by the 3 AM dream: #953.

Nothing here is a defect in the guard's implementation. It does exactly what its docstring specifies. The problem is that the sweep cannot measure the guard's coverage, only its execution.

Why the instrument can't see it

By deliberate design (and it's a good one for drift), scripts/kg_ephemeral_sweep.py imports is_ephemeral from src/pinky_memory/ephemeral_guard.py — the same function the write-time guard calls:

"The recurring sweep imports the SAME is_ephemeral from here, so the regex lives in exactly one place and the two halves can never drift."

The consequence is structural: a name the guard fails to block is a name the sweep cannot count. The two halves can never disagree, so the sweep reports 0 for any pattern outside the shared dictionary — forever, and indistinguishably from genuine success. The measurement instrument is blind in exactly the same shape as the thing it measures.

Fifty-two days of 0 reads as "the guard solved it, deprioritize." The graph says otherwise.

What's escaping, measured

EPHEMERAL_PATTERNS requires a prefix word (PR #635, issue #501, release 26.05.094), an owner/repo#NNN form, or the PinkyBot \d{2}\.\d{2}\.\d{3} stamp. Uncovered forms actually present in barsik/data/memory.db, IPv4 excluded:

form entities edges (active) examples
bare #NNN — no prefix word 88 139 (139) #953, #692, #145
PR N / issue N — no # 20 178 (178) PR1, PR2, issue 327
semver vX.Y.Z 31 42 (41) v2.1.214, v0.2.82
semver X.Y.Z 37 54 (54) 0.2.122, 9.125.0
bare integer (ambiguous — see below) 95 144 (144) 9, 383, 400000
total 271 557 (556)

Split by creation date against the guard's ship date: 5 pre-guard, 281 post-guard. By month: June 243, July 37, August 1 (partial). July's ~1.2/night is the steady-state rate — low, but not zero, and cumulative.

bare #NNN is the one that matters most: it's how issues get cited in practice, including throughout my own memory and messages, so it's the highest-frequency form the extractor sees.

Ambiguity flagged honestly: the bare integer row is not clearly ephemeral — 400000 could be a meaningful quantity in some context. Excluding that row entirely still leaves 176 unambiguous pure-ID entities, essentially all post-guard. I'd treat 176 as the defensible figure and 271 as the upper bound.

IPv4 was excluded deliberately — my first pass counted 10.0.0.209, 10.0.0.152 and 127.0.0.1 as ephemeral, which is wrong: those are the Mini, the Pi and localhost, durable infrastructure nodes. Any pattern widening must exclude dotted quads, or it will delete the fleet's addressing.

Scale note

The docstring records the patterns as "soak-validated against barsik's live ~392-entity graph: 49 true positives, ZERO false positives." That graph now holds 18,279 entities and 19,031 triples — roughly 46× the validation corpus. The zero-false-positive result still appears to hold (no evidence of over-blocking), but a dictionary validated at 392 entities is being trusted at 18k.

Suggested direction (not done — deliberately)

I have not widened the patterns or deleted anything. Widening a delete-pattern against a live memory graph needs review, and the sweep's conservatism ("miss-and-recatch beats false-block") is correct. Proposals, in order:

  1. Break the shared-blindness property. The sweep should keep using is_ephemeral for deletion but report a second, wider candidate-only diagnostic count that is never auto-deleted. That restores an independent instrument without risking a false delete. This is the fix that matters — the others are one-time cleanups.
  2. Extend EPHEMERAL_PATTERNS for bare #NNN, prefix-without-hash (PR1, issue 327), and semver stamps. Must exclude IPv4 and should probably leave bare integers alone.
  3. One-time cleanup of the 176 unambiguous existing nodes, via the sweep's normal backup + JSONL path.
  4. Log n_entities_total in each sweep record, so a future reader can see the zero was taken against an 18k graph rather than a 392-entity one.

Reproduction

python3 scripts/kg_ephemeral_sweep.py data/agents/barsik/data/memory.db   # dry run: 0
python3 -c "
from pinky_memory.ephemeral_guard import is_ephemeral
print([(n, is_ephemeral(n)) for n in ['PR #124','#953','PR1','v2.1.214','26.07.029']])"
# -> PR #124 True, #953 False, PR1 False, v2.1.214 False, 26.07.029 True

🤖 Filed by Barsik

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions