Knowledge Audit
Systematic review of stored memories to maintain quality. Finds duplicates, detects contradictions, flags stale entries, and consolidates overlapping memories.
Steps
Scope the audit:
- If topic specified:
memory(action="search", query="[topic]") to find all related memories
- If "all":
memory(action="list") to get full inventory, then memory(action="stats") for overview
- Group memories by tag/category for systematic review
Identify duplicates:
- Search for memories with similar content or overlapping keywords
- Compare pairs that cover the same topic
- Decision: keep the more detailed/recent one, delete the other
- Use
memory(action="delete", id="[duplicate-id]") for removals
Detect contradictions:
- Look for memories that make opposing claims about the same topic
- Examples: "Use library A" vs "Switched to library B", conflicting conventions
- Decision tree:
- Both have dates -> keep the newer one (it supersedes)
- Neither has date -> ask user which is current
- Both are valid (context-dependent) -> update both to clarify their scope
- Update the surviving memory to note it supersedes the old one
Flag stale entries:
- Memories referencing specific versions that are now outdated
- Memories about temporary workarounds that may have been resolved
- Memories about tools/libraries that have been replaced
- Action: mark as stale with
memory(action="update", ...) adding [STALE] prefix, or delete if clearly obsolete
Consolidate overlapping memories:
- Multiple memories about the same topic that each have partial info
- Merge into a single comprehensive memory
- Steps: create new consolidated memory -> verify retrieval -> delete originals
- Use
memory(action="consolidate", ...) if available, otherwise manual merge
Produce audit report:
## Knowledge Audit — [topic/all] — [date]
### Summary
- Total memories reviewed: [N]
- Duplicates removed: [N]
- Contradictions resolved: [N]
- Stale entries flagged/removed: [N]
- Memories consolidated: [N merged into M]
### Actions Taken
- [list of specific changes]
### Recommendations
- [any patterns noticed, e.g., "many memories lack WHY context"]
Staleness Indicators
- References to specific version numbers (check if still current)
- Contains "temporary", "workaround", "until X is fixed"
- References removed/renamed files, deprecated APIs, old URLs
- Predates a major migration or refactor (check project history)
- Contains "TODO" or "will be" — was it done?
Contradiction Resolution Rules
- Explicit supersession: If memory B says "switched from A to B", delete memory about using A
- Scope difference: "Use X for backend" and "Use Y for frontend" are NOT contradictions
- Evolution: "Started with X" and "Migrated to Y" — keep Y, delete X (unless X context is still relevant)
- Ambiguous: When unclear, DO NOT delete — ask the user
When to Use
- Periodically (monthly or after major project changes)
- When memory search returns confusing or contradictory results
- After a major migration or architecture change
- When starting a new phase of a project
- When memory count grows large and retrieval quality degrades
Phase 3: Temporal KG Audit (v2.0+)
Phase 3 ships a temporal knowledge graph (entities + edges + bitemporal
versioning + supersession). The audit checklist now also covers KG
hygiene:
KG-aware audit dimensions
Stale entities: entity rows that no longer link to any active
memory (their last memory_entity_links row points at an archived /
superseded memory).
- Detect:
memory(action="entity_search", name="<entity>") returning
0 currently-valid hits → candidate stale.
- Action: confirm with the user, then delete the orphaned entity row
(cascade removes edges).
Orphan edges: edges in memory_edges whose source or target
memory_entities row was deleted but the edge survived.
- Detect: server logs show "edge with missing endpoint" warnings, or
entity_graph returns nodes referenced from edges that aren't in
the nodes list.
- Action: ask user; either re-extract the originating capture or
hand-delete the edge by id.
Contradicting / superseded chains: a memory in a supersession
chain still surfaces in default memory.get results because someone
left valid_to = NULL on an old fact.
- Detect:
memory(action="history", entity_id=<x>) returning multiple
rows with valid_to = NULL for the same entity.
- Action: pick the most-recent / most-correct row and update
valid_to on the others to the supersession timestamp.
Bitemporal drift: capture has no valid_from set, falls outside
the bitemporal index. Usually a pre-Phase-3 row that was missed by
backfill, or a manual db.add that bypassed the capture pipeline.
- Detect: SQL spot check
SELECT COUNT(*) FROM memories WHERE valid_from IS NULL.
- Action: re-run the Phase 3 backfill (
MemoryDB._backfill_phase3_temporal)
or update the rows manually.
Audit-trail integrity: every mutation (insert / update / supersede
/ delete) should write a memory_audit row with prev_state_hash
and new_state_hash. A gap in the chain (audit row absent for an
update) signals a bug or out-of-band write.
- Detect:
SELECT m.id FROM memories m LEFT JOIN memory_audit a ON a.memory_id = m.id WHERE a.id IS NULL.
- Action: investigate which path wrote the row; do NOT rewrite the
audit history (preserves tamper-detection guarantees).
When to run the temporal sub-audit
- After running the Phase 1/2 "Knowledge Audit" steps above.
- After importing a Phase 2 passport bundle (legacy schema → can leave
bitemporal columns NULL).
- After any large
memory(action="capture", auto=True) batch with
KG_AUTO_ENABLED=true (entity resolution may need tuning).
- Before exporting a Phase 3 passport bundle (so receiver gets a clean KG).
1---2name: knowledge-audit3description: Review and clean up stored memories — find duplicates, contradictions, stale entries, and consolidate4---56# Knowledge Audit78Systematic review of stored memories to maintain quality. Finds duplicates, detects contradictions, flags stale entries, and consolidates overlapping memories.910## Steps11121. **Scope the audit**:13 - If topic specified: `memory(action="search", query="[topic]")` to find all related memories14 - If "all": `memory(action="list")` to get full inventory, then `memory(action="stats")` for overview15 - Group memories by tag/category for systematic review16172. **Identify duplicates**:18 - Search for memories with similar content or overlapping keywords19 - Compare pairs that cover the same topic20 - Decision: keep the more detailed/recent one, delete the other21 - Use `memory(action="delete", id="[duplicate-id]")` for removals22233. **Detect contradictions**:24 - Look for memories that make opposing claims about the same topic25 - Examples: "Use library A" vs "Switched to library B", conflicting conventions26 - Decision tree:27 - Both have dates -> keep the newer one (it supersedes)28 - Neither has date -> ask user which is current29 - Both are valid (context-dependent) -> update both to clarify their scope30 - Update the surviving memory to note it supersedes the old one31324. **Flag stale entries**:33 - Memories referencing specific versions that are now outdated34 - Memories about temporary workarounds that may have been resolved35 - Memories about tools/libraries that have been replaced36 - Action: mark as stale with `memory(action="update", ...)` adding `[STALE]` prefix, or delete if clearly obsolete37385. **Consolidate overlapping memories**:39 - Multiple memories about the same topic that each have partial info40 - Merge into a single comprehensive memory41 - Steps: create new consolidated memory -> verify retrieval -> delete originals42 - Use `memory(action="consolidate", ...)` if available, otherwise manual merge43446. **Produce audit report**:45 ```46 ## Knowledge Audit — [topic/all] — [date]4748 ### Summary49 - Total memories reviewed: [N]50 - Duplicates removed: [N]51 - Contradictions resolved: [N]52 - Stale entries flagged/removed: [N]53 - Memories consolidated: [N merged into M]5455 ### Actions Taken56 - [list of specific changes]5758 ### Recommendations59 - [any patterns noticed, e.g., "many memories lack WHY context"]60 ```6162## Staleness Indicators6364- References to specific version numbers (check if still current)65- Contains "temporary", "workaround", "until X is fixed"66- References removed/renamed files, deprecated APIs, old URLs67- Predates a major migration or refactor (check project history)68- Contains "TODO" or "will be" — was it done?6970## Contradiction Resolution Rules7172- **Explicit supersession**: If memory B says "switched from A to B", delete memory about using A73- **Scope difference**: "Use X for backend" and "Use Y for frontend" are NOT contradictions74- **Evolution**: "Started with X" and "Migrated to Y" — keep Y, delete X (unless X context is still relevant)75- **Ambiguous**: When unclear, DO NOT delete — ask the user7677## When to Use7879- Periodically (monthly or after major project changes)80- When memory search returns confusing or contradictory results81- After a major migration or architecture change82- When starting a new phase of a project83- When memory count grows large and retrieval quality degrades8485## Phase 3: Temporal KG Audit (v2.0+)8687Phase 3 ships a temporal knowledge graph (entities + edges + bitemporal88versioning + supersession). The audit checklist now also covers KG89hygiene:9091### KG-aware audit dimensions92937. **Stale entities**: entity rows that no longer link to any active94 memory (their last `memory_entity_links` row points at an archived /95 superseded memory).96 - Detect: `memory(action="entity_search", name="<entity>")` returning97 0 currently-valid hits → candidate stale.98 - Action: confirm with the user, then delete the orphaned entity row99 (cascade removes edges).1001018. **Orphan edges**: edges in `memory_edges` whose source or target102 `memory_entities` row was deleted but the edge survived.103 - Detect: server logs show "edge with missing endpoint" warnings, or104 `entity_graph` returns nodes referenced from edges that aren't in105 the nodes list.106 - Action: ask user; either re-extract the originating capture or107 hand-delete the edge by id.1081099. **Contradicting / superseded chains**: a memory in a supersession110 chain still surfaces in default `memory.get` results because someone111 left `valid_to = NULL` on an old fact.112 - Detect: `memory(action="history", entity_id=<x>)` returning multiple113 rows with `valid_to = NULL` for the same entity.114 - Action: pick the most-recent / most-correct row and update115 `valid_to` on the others to the supersession timestamp.11611710. **Bitemporal drift**: capture has no `valid_from` set, falls outside118 the bitemporal index. Usually a pre-Phase-3 row that was missed by119 backfill, or a manual `db.add` that bypassed the capture pipeline.120 - Detect: SQL spot check121 `SELECT COUNT(*) FROM memories WHERE valid_from IS NULL`.122 - Action: re-run the Phase 3 backfill (`MemoryDB._backfill_phase3_temporal`)123 or update the rows manually.12412511. **Audit-trail integrity**: every mutation (insert / update / supersede126 / delete) should write a `memory_audit` row with `prev_state_hash`127 and `new_state_hash`. A gap in the chain (audit row absent for an128 update) signals a bug or out-of-band write.129 - Detect: `SELECT m.id FROM memories m LEFT JOIN memory_audit a130 ON a.memory_id = m.id WHERE a.id IS NULL`.131 - Action: investigate which path wrote the row; do NOT rewrite the132 audit history (preserves tamper-detection guarantees).133134### When to run the temporal sub-audit135136- After running the Phase 1/2 "Knowledge Audit" steps above.137- After importing a Phase 2 passport bundle (legacy schema → can leave138 bitemporal columns NULL).139- After any large `memory(action="capture", auto=True)` batch with140 `KG_AUTO_ENABLED=true` (entity resolution may need tuning).141- Before exporting a Phase 3 passport bundle (so receiver gets a clean KG).