htm 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.architecture/decisions/adrs/001-use-postgresql-timescaledb-storage.md +227 -0
- data/.architecture/decisions/adrs/002-two-tier-memory-architecture.md +322 -0
- data/.architecture/decisions/adrs/003-ollama-default-embedding-provider.md +339 -0
- data/.architecture/decisions/adrs/004-multi-robot-shared-memory-hive-mind.md +374 -0
- data/.architecture/decisions/adrs/005-rag-based-retrieval-with-hybrid-search.md +443 -0
- data/.architecture/decisions/adrs/006-context-assembly-strategies.md +444 -0
- data/.architecture/decisions/adrs/007-working-memory-eviction-strategy.md +461 -0
- data/.architecture/decisions/adrs/008-robot-identification-system.md +550 -0
- data/.architecture/decisions/adrs/009-never-forget-explicit-deletion-only.md +570 -0
- data/.architecture/decisions/adrs/010-redis-working-memory-rejected.md +323 -0
- data/.architecture/decisions/adrs/011-database-side-embedding-generation-with-pgai.md +585 -0
- data/.architecture/decisions/adrs/012-llm-driven-ontology-topic-extraction.md +583 -0
- data/.architecture/decisions/adrs/013-activerecord-orm-and-many-to-many-tagging.md +299 -0
- data/.architecture/decisions/adrs/014-client-side-embedding-generation-workflow.md +569 -0
- data/.architecture/decisions/adrs/015-hierarchical-tag-ontology-and-llm-extraction.md +701 -0
- data/.architecture/decisions/adrs/016-async-embedding-and-tag-generation.md +694 -0
- data/.architecture/members.yml +144 -0
- data/.architecture/reviews/2025-10-29-llm-configuration-and-async-processing-review.md +1137 -0
- data/.architecture/reviews/initial-system-analysis.md +330 -0
- data/.envrc +32 -0
- data/.irbrc +145 -0
- data/CHANGELOG.md +150 -0
- data/COMMITS.md +196 -0
- data/LICENSE +21 -0
- data/README.md +1347 -0
- data/Rakefile +51 -0
- data/SETUP.md +268 -0
- data/config/database.yml +67 -0
- data/db/migrate/20250101000001_enable_extensions.rb +14 -0
- data/db/migrate/20250101000002_create_robots.rb +14 -0
- data/db/migrate/20250101000003_create_nodes.rb +42 -0
- data/db/migrate/20250101000005_create_tags.rb +38 -0
- data/db/migrate/20250101000007_add_node_vector_indexes.rb +30 -0
- data/db/schema.sql +473 -0
- data/db/seed_data/README.md +100 -0
- data/db/seed_data/presidents.md +136 -0
- data/db/seed_data/states.md +151 -0
- data/db/seeds.rb +208 -0
- data/dbdoc/README.md +173 -0
- data/dbdoc/public.node_stats.md +48 -0
- data/dbdoc/public.node_stats.svg +41 -0
- data/dbdoc/public.node_tags.md +40 -0
- data/dbdoc/public.node_tags.svg +112 -0
- data/dbdoc/public.nodes.md +54 -0
- data/dbdoc/public.nodes.svg +118 -0
- data/dbdoc/public.nodes_tags.md +39 -0
- data/dbdoc/public.nodes_tags.svg +112 -0
- data/dbdoc/public.ontology_structure.md +48 -0
- data/dbdoc/public.ontology_structure.svg +38 -0
- data/dbdoc/public.operations_log.md +42 -0
- data/dbdoc/public.operations_log.svg +130 -0
- data/dbdoc/public.relationships.md +39 -0
- data/dbdoc/public.relationships.svg +41 -0
- data/dbdoc/public.robot_activity.md +46 -0
- data/dbdoc/public.robot_activity.svg +35 -0
- data/dbdoc/public.robots.md +35 -0
- data/dbdoc/public.robots.svg +90 -0
- data/dbdoc/public.schema_migrations.md +29 -0
- data/dbdoc/public.schema_migrations.svg +26 -0
- data/dbdoc/public.tags.md +35 -0
- data/dbdoc/public.tags.svg +60 -0
- data/dbdoc/public.topic_relationships.md +45 -0
- data/dbdoc/public.topic_relationships.svg +32 -0
- data/dbdoc/schema.json +1437 -0
- data/dbdoc/schema.svg +154 -0
- data/docs/api/database.md +806 -0
- data/docs/api/embedding-service.md +532 -0
- data/docs/api/htm.md +797 -0
- data/docs/api/index.md +259 -0
- data/docs/api/long-term-memory.md +1096 -0
- data/docs/api/working-memory.md +665 -0
- data/docs/architecture/adrs/001-postgresql-timescaledb.md +314 -0
- data/docs/architecture/adrs/002-two-tier-memory.md +411 -0
- data/docs/architecture/adrs/003-ollama-embeddings.md +421 -0
- data/docs/architecture/adrs/004-hive-mind.md +437 -0
- data/docs/architecture/adrs/005-rag-retrieval.md +531 -0
- data/docs/architecture/adrs/006-context-assembly.md +496 -0
- data/docs/architecture/adrs/007-eviction-strategy.md +645 -0
- data/docs/architecture/adrs/008-robot-identification.md +625 -0
- data/docs/architecture/adrs/009-never-forget.md +648 -0
- data/docs/architecture/adrs/010-redis-working-memory-rejected.md +323 -0
- data/docs/architecture/adrs/011-pgai-integration.md +494 -0
- data/docs/architecture/adrs/index.md +215 -0
- data/docs/architecture/hive-mind.md +736 -0
- data/docs/architecture/index.md +351 -0
- data/docs/architecture/overview.md +538 -0
- data/docs/architecture/two-tier-memory.md +873 -0
- data/docs/assets/css/custom.css +83 -0
- data/docs/assets/images/htm-core-components.svg +63 -0
- data/docs/assets/images/htm-database-schema.svg +93 -0
- data/docs/assets/images/htm-hive-mind-architecture.svg +125 -0
- data/docs/assets/images/htm-importance-scoring-framework.svg +83 -0
- data/docs/assets/images/htm-layered-architecture.svg +71 -0
- data/docs/assets/images/htm-long-term-memory-architecture.svg +115 -0
- data/docs/assets/images/htm-working-memory-architecture.svg +120 -0
- data/docs/assets/images/htm.jpg +0 -0
- data/docs/assets/images/htm_demo.gif +0 -0
- data/docs/assets/js/mathjax.js +18 -0
- data/docs/assets/videos/htm_video.mp4 +0 -0
- data/docs/database_rake_tasks.md +322 -0
- data/docs/development/contributing.md +787 -0
- data/docs/development/index.md +336 -0
- data/docs/development/schema.md +596 -0
- data/docs/development/setup.md +719 -0
- data/docs/development/testing.md +819 -0
- data/docs/guides/adding-memories.md +824 -0
- data/docs/guides/context-assembly.md +1009 -0
- data/docs/guides/getting-started.md +577 -0
- data/docs/guides/index.md +118 -0
- data/docs/guides/long-term-memory.md +941 -0
- data/docs/guides/multi-robot.md +866 -0
- data/docs/guides/recalling-memories.md +927 -0
- data/docs/guides/search-strategies.md +953 -0
- data/docs/guides/working-memory.md +717 -0
- data/docs/index.md +214 -0
- data/docs/installation.md +477 -0
- data/docs/multi_framework_support.md +519 -0
- data/docs/quick-start.md +655 -0
- data/docs/setup_local_database.md +302 -0
- data/docs/using_rake_tasks_in_your_app.md +383 -0
- data/examples/basic_usage.rb +93 -0
- data/examples/cli_app/README.md +317 -0
- data/examples/cli_app/htm_cli.rb +270 -0
- data/examples/custom_llm_configuration.rb +183 -0
- data/examples/example_app/Rakefile +71 -0
- data/examples/example_app/app.rb +206 -0
- data/examples/sinatra_app/Gemfile +21 -0
- data/examples/sinatra_app/app.rb +335 -0
- data/lib/htm/active_record_config.rb +113 -0
- data/lib/htm/configuration.rb +342 -0
- data/lib/htm/database.rb +594 -0
- data/lib/htm/embedding_service.rb +115 -0
- data/lib/htm/errors.rb +34 -0
- data/lib/htm/job_adapter.rb +154 -0
- data/lib/htm/jobs/generate_embedding_job.rb +65 -0
- data/lib/htm/jobs/generate_tags_job.rb +82 -0
- data/lib/htm/long_term_memory.rb +965 -0
- data/lib/htm/models/node.rb +109 -0
- data/lib/htm/models/node_tag.rb +33 -0
- data/lib/htm/models/robot.rb +52 -0
- data/lib/htm/models/tag.rb +76 -0
- data/lib/htm/railtie.rb +76 -0
- data/lib/htm/sinatra.rb +157 -0
- data/lib/htm/tag_service.rb +135 -0
- data/lib/htm/tasks.rb +38 -0
- data/lib/htm/version.rb +5 -0
- data/lib/htm/working_memory.rb +182 -0
- data/lib/htm.rb +400 -0
- data/lib/tasks/db.rake +19 -0
- data/lib/tasks/htm.rake +147 -0
- data/lib/tasks/jobs.rake +312 -0
- data/mkdocs.yml +190 -0
- data/scripts/install_local_database.sh +309 -0
- metadata +341 -0
|
@@ -0,0 +1,648 @@
|
|
|
1
|
+
# ADR-009: Never-Forget Philosophy with Explicit Deletion
|
|
2
|
+
|
|
3
|
+
**Status**: Accepted
|
|
4
|
+
|
|
5
|
+
**Date**: 2025-10-25
|
|
6
|
+
|
|
7
|
+
**Decision Makers**: Dewayne VanHoozer, Claude (Anthropic)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Quick Summary
|
|
12
|
+
|
|
13
|
+
HTM implements a **never-forget philosophy** where memories are never automatically deleted. Eviction only moves memories from working to long-term storage. Deletion requires explicit confirmation (`:confirmed` symbol) and is permanently logged for audit trails.
|
|
14
|
+
|
|
15
|
+
**Why**: LLMs need persistent, never-forgetting memory for long-term context. Automatic deletion causes surprise, debugging difficulties, and lost knowledge.
|
|
16
|
+
|
|
17
|
+
**Impact**: Predictable behavior with complete data preservation, at the cost of unbounded storage growth and manual cleanup responsibility.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Context
|
|
22
|
+
|
|
23
|
+
Traditional memory systems for LLMs face a critical design decision: when should memories be deleted?
|
|
24
|
+
|
|
25
|
+
### Alternative Approaches
|
|
26
|
+
|
|
27
|
+
1. **Automatic deletion**: LRU cache eviction, TTL expiration, capacity limits
|
|
28
|
+
2. **Never delete**: Unlimited growth, storage costs, degraded performance
|
|
29
|
+
3. **Manual deletion**: User explicitly deletes memories
|
|
30
|
+
4. **Hybrid**: Automatic archival + manual deletion for permanent removal
|
|
31
|
+
|
|
32
|
+
### Key Challenges
|
|
33
|
+
|
|
34
|
+
- **LLM context loss**: Deleting memories loses valuable knowledge
|
|
35
|
+
- **User surprise**: Automatic deletion feels like "forgetting" without consent
|
|
36
|
+
- **Debugging**: Hard to debug if memories disappear automatically
|
|
37
|
+
- **Storage costs**: Unlimited storage is expensive
|
|
38
|
+
- **Performance**: Large datasets slow down queries
|
|
39
|
+
|
|
40
|
+
HTM's core purpose is to provide **persistent, never-forgetting memory** for LLM robots. The philosophy: "never forget unless explicitly told."
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Decision
|
|
45
|
+
|
|
46
|
+
We will implement a **never-forget philosophy** where:
|
|
47
|
+
|
|
48
|
+
1. Memories are never automatically deleted
|
|
49
|
+
2. Eviction only moves memories from working to long-term storage
|
|
50
|
+
3. Deletion requires explicit user confirmation
|
|
51
|
+
4. Confirmation must be `:confirmed` symbol to prevent accidental deletion
|
|
52
|
+
5. All deletions are logged for audit trail
|
|
53
|
+
|
|
54
|
+
### Deletion API
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
# Attempting to delete without confirmation raises error
|
|
58
|
+
htm.forget("key_to_delete")
|
|
59
|
+
# => ArgumentError: Must pass confirm: :confirmed to delete
|
|
60
|
+
|
|
61
|
+
# Explicit confirmation required
|
|
62
|
+
htm.forget("key_to_delete", confirm: :confirmed)
|
|
63
|
+
# => true (deleted successfully)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Eviction vs Deletion
|
|
67
|
+
|
|
68
|
+
!!! info "Critical Distinction"
|
|
69
|
+
**Eviction (automatic, safe)**:
|
|
70
|
+
|
|
71
|
+
- Triggered by working memory capacity limit
|
|
72
|
+
- Moves memories from working memory to long-term memory
|
|
73
|
+
- NO data loss, memories remain recallable
|
|
74
|
+
- Logged as 'evict' operation
|
|
75
|
+
|
|
76
|
+
**Deletion (explicit, destructive)**:
|
|
77
|
+
|
|
78
|
+
- Triggered only by user calling `forget(confirm: :confirmed)`
|
|
79
|
+
- Removes memory from both working and long-term storage
|
|
80
|
+
- PERMANENT data loss
|
|
81
|
+
- Logged as 'forget' operation
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Rationale
|
|
86
|
+
|
|
87
|
+
### Why Never-Forget?
|
|
88
|
+
|
|
89
|
+
**LLMs need long-term context**:
|
|
90
|
+
|
|
91
|
+
- Architectural decisions made months ago still matter
|
|
92
|
+
- User preferences should persist across sessions
|
|
93
|
+
- Bug fixes and resolutions are valuable knowledge
|
|
94
|
+
- Conversation history builds understanding over time
|
|
95
|
+
|
|
96
|
+
**Automatic deletion causes problems**:
|
|
97
|
+
|
|
98
|
+
- Surprise: User asks "didn't we discuss this?" → memory gone
|
|
99
|
+
- Debugging: Can't debug deleted memories
|
|
100
|
+
- Inconsistency: Same query returns different results over time
|
|
101
|
+
- Lost knowledge: Critical information disappears silently
|
|
102
|
+
|
|
103
|
+
**Two-tier architecture enables never-forget**:
|
|
104
|
+
|
|
105
|
+
- Working memory: Token-limited, evicts to long-term
|
|
106
|
+
- Long-term memory: Unlimited, persistent PostgreSQL
|
|
107
|
+
- Eviction ≠ deletion, just moves to cold storage
|
|
108
|
+
- Recall brings memories back to working memory
|
|
109
|
+
|
|
110
|
+
### Why Explicit Confirmation?
|
|
111
|
+
|
|
112
|
+
**Prevent accidental deletion**:
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
# Easy typo or mistake
|
|
116
|
+
htm.forget("important_key") # REJECTED - raises error
|
|
117
|
+
|
|
118
|
+
# Must be intentional
|
|
119
|
+
htm.forget("important_key", confirm: :confirmed) # Allowed
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Confirmation is a speed bump**:
|
|
123
|
+
|
|
124
|
+
- Forces user to think before deleting
|
|
125
|
+
- Symbol `:confirmed` (not boolean) prevents `confirm: true` shortcuts
|
|
126
|
+
- Clear intent signal in code review
|
|
127
|
+
|
|
128
|
+
**Audit trail for safety**:
|
|
129
|
+
|
|
130
|
+
- All deletions logged with robot_id and timestamp
|
|
131
|
+
- Can investigate "who deleted this?"
|
|
132
|
+
- Provides recovery information (log has the deleted value)
|
|
133
|
+
|
|
134
|
+
### Why Log Before Deleting?
|
|
135
|
+
|
|
136
|
+
**Foreign key constraint safety**:
|
|
137
|
+
|
|
138
|
+
```ruby
|
|
139
|
+
# Log operation BEFORE deleting
|
|
140
|
+
@long_term_memory.log_operation(
|
|
141
|
+
operation: 'forget',
|
|
142
|
+
node_id: node_id, # Still exists
|
|
143
|
+
robot_id: @robot_id,
|
|
144
|
+
details: { key: key }
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# Now safe to delete
|
|
148
|
+
@long_term_memory.delete(key)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Audit trail preservation**:
|
|
152
|
+
|
|
153
|
+
- Deletion log entry survives even if something goes wrong
|
|
154
|
+
- Can reconstruct what was deleted and when
|
|
155
|
+
- Supports future "undo delete" feature
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Implementation Details
|
|
160
|
+
|
|
161
|
+
### Forget Method
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
def forget(key, confirm: false)
|
|
165
|
+
raise ArgumentError, "Must pass confirm: :confirmed to delete" unless confirm == :confirmed
|
|
166
|
+
|
|
167
|
+
node_id = @long_term_memory.get_node_id(key)
|
|
168
|
+
|
|
169
|
+
# Log operation BEFORE deleting (audit trail)
|
|
170
|
+
@long_term_memory.log_operation(
|
|
171
|
+
operation: 'forget',
|
|
172
|
+
node_id: node_id,
|
|
173
|
+
robot_id: @robot_id,
|
|
174
|
+
details: { key: key }
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Delete from long-term memory and working memory
|
|
178
|
+
@long_term_memory.delete(key)
|
|
179
|
+
@working_memory.remove(key)
|
|
180
|
+
|
|
181
|
+
update_robot_activity
|
|
182
|
+
true
|
|
183
|
+
end
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Consequences
|
|
189
|
+
|
|
190
|
+
### Positive
|
|
191
|
+
|
|
192
|
+
- Never lose knowledge: Memories persist unless explicitly deleted
|
|
193
|
+
- Predictable behavior: No surprise deletions, no data loss
|
|
194
|
+
- Debugging friendly: All memories available for analysis
|
|
195
|
+
- Audit trail: Every deletion logged with who/when/what
|
|
196
|
+
- Safe eviction: Working memory overflow doesn't lose data
|
|
197
|
+
- Recallable: Evicted memories return via recall()
|
|
198
|
+
- Intentional deletion: Confirmation prevents accidents
|
|
199
|
+
|
|
200
|
+
### Negative
|
|
201
|
+
|
|
202
|
+
- Unbounded growth: Database grows indefinitely without cleanup
|
|
203
|
+
- Storage costs: Long-term storage has financial cost
|
|
204
|
+
- Query performance: Larger datasets slow down searches
|
|
205
|
+
- Manual cleanup: User must periodically delete unneeded memories
|
|
206
|
+
- No automatic expiration: Can't set TTL for temporary memories
|
|
207
|
+
- Privacy concerns: Sensitive data persists until deleted
|
|
208
|
+
|
|
209
|
+
### Neutral
|
|
210
|
+
|
|
211
|
+
- User responsibility: User must manage memory lifecycle
|
|
212
|
+
- Explicit is better: Pythonic philosophy, clear intent
|
|
213
|
+
- Retention policies: Future feature, not v1
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Use Cases
|
|
218
|
+
|
|
219
|
+
### Use Case 1: Accidental Deletion Attempt
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
# User typo or mistake
|
|
223
|
+
htm.forget("important_decision")
|
|
224
|
+
|
|
225
|
+
# Result: ArgumentError raised
|
|
226
|
+
# => ArgumentError: Must pass confirm: :confirmed to delete
|
|
227
|
+
|
|
228
|
+
# Memory remains safe
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Use Case 2: Intentional Deletion
|
|
232
|
+
|
|
233
|
+
```ruby
|
|
234
|
+
# User wants to delete temporary test data
|
|
235
|
+
htm.add_node("test_key", "temporary test data", importance: 1.0)
|
|
236
|
+
|
|
237
|
+
# Later: delete intentionally
|
|
238
|
+
htm.forget("test_key", confirm: :confirmed)
|
|
239
|
+
# => true (deleted)
|
|
240
|
+
|
|
241
|
+
# Deletion logged for audit trail
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Use Case 3: Eviction (Not Deletion)
|
|
245
|
+
|
|
246
|
+
```ruby
|
|
247
|
+
# Working memory full (128,000 tokens)
|
|
248
|
+
# Add large new memory (10,000 tokens)
|
|
249
|
+
|
|
250
|
+
htm.add_node("new_large_memory", large_text, importance: 7.0)
|
|
251
|
+
|
|
252
|
+
# Result: HTM evicts low-importance memories to make space
|
|
253
|
+
# Evicted memories moved to long-term storage (NOT deleted)
|
|
254
|
+
# Can be recalled later:
|
|
255
|
+
|
|
256
|
+
memories = htm.recall(timeframe: "last month", topic: "evicted topic")
|
|
257
|
+
# => Evicted memories returned
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Use Case 4: Audit Trail Query
|
|
261
|
+
|
|
262
|
+
```sql
|
|
263
|
+
-- Who deleted this memory?
|
|
264
|
+
SELECT robot_id, created_at, details
|
|
265
|
+
FROM operations_log
|
|
266
|
+
WHERE operation = 'forget'
|
|
267
|
+
AND details->>'key' = 'important_key'
|
|
268
|
+
|
|
269
|
+
-- Result:
|
|
270
|
+
-- robot_id: "f47ac10b-..."
|
|
271
|
+
-- created_at: 2025-10-25 14:32:15
|
|
272
|
+
-- details: {"key": "important_key"}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Use Case 5: Bulk Cleanup (Manual)
|
|
276
|
+
|
|
277
|
+
```ruby
|
|
278
|
+
# User wants to clean up old test data
|
|
279
|
+
test_keys = [
|
|
280
|
+
"test_001",
|
|
281
|
+
"test_002",
|
|
282
|
+
"test_003"
|
|
283
|
+
]
|
|
284
|
+
|
|
285
|
+
test_keys.each do |key|
|
|
286
|
+
htm.forget(key, confirm: :confirmed)
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# All deletions logged individually
|
|
290
|
+
# User must explicitly confirm each deletion
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Use Case 6: Never-Forget in Practice
|
|
294
|
+
|
|
295
|
+
```ruby
|
|
296
|
+
# Session 1: Important decision
|
|
297
|
+
htm.add_node("decision_001",
|
|
298
|
+
"We decided to use PostgreSQL for HTM storage",
|
|
299
|
+
type: :decision,
|
|
300
|
+
importance: 10.0)
|
|
301
|
+
|
|
302
|
+
# ... 90 days later, many sessions, many memories added ...
|
|
303
|
+
# Working memory evicted this decision to long-term storage
|
|
304
|
+
|
|
305
|
+
# Session 100: User asks about database choice
|
|
306
|
+
memories = htm.recall(timeframe: "last 3 months", topic: "database storage")
|
|
307
|
+
|
|
308
|
+
# Result: Decision recalled from long-term memory
|
|
309
|
+
# Never forgotten, always available
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## Deletion Lifecycle
|
|
315
|
+
|
|
316
|
+
### 1. User Initiates Deletion
|
|
317
|
+
|
|
318
|
+
```ruby
|
|
319
|
+
htm.forget("key_to_delete", confirm: :confirmed)
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### 2. Validation
|
|
323
|
+
|
|
324
|
+
```ruby
|
|
325
|
+
raise ArgumentError, "Must pass confirm: :confirmed to delete" unless confirm == :confirmed
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### 3. Retrieve Node ID
|
|
329
|
+
|
|
330
|
+
```ruby
|
|
331
|
+
node_id = @long_term_memory.get_node_id("key_to_delete")
|
|
332
|
+
# => 42
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### 4. Log Operation (Before Deletion)
|
|
336
|
+
|
|
337
|
+
```ruby
|
|
338
|
+
@long_term_memory.log_operation(
|
|
339
|
+
operation: 'forget',
|
|
340
|
+
node_id: 42, # Still exists at this point
|
|
341
|
+
robot_id: @robot_id,
|
|
342
|
+
details: { key: "key_to_delete" }
|
|
343
|
+
)
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### 5. Delete from Long-Term Memory
|
|
347
|
+
|
|
348
|
+
```sql
|
|
349
|
+
DELETE FROM nodes WHERE key = 'key_to_delete'
|
|
350
|
+
|
|
351
|
+
-- Cascades to:
|
|
352
|
+
-- - relationships (foreign key cascade)
|
|
353
|
+
-- - tags (foreign key cascade)
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### 6. Remove from Working Memory
|
|
357
|
+
|
|
358
|
+
```ruby
|
|
359
|
+
@working_memory.remove("key_to_delete")
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### 7. Update Robot Activity
|
|
363
|
+
|
|
364
|
+
```ruby
|
|
365
|
+
@long_term_memory.update_robot_activity(@robot_id)
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### 8. Return Success
|
|
369
|
+
|
|
370
|
+
```ruby
|
|
371
|
+
return true
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## Performance Characteristics
|
|
377
|
+
|
|
378
|
+
### Deletion Performance
|
|
379
|
+
|
|
380
|
+
- **Node ID lookup**: O(log n) with index on key
|
|
381
|
+
- **Log operation**: O(1) insert
|
|
382
|
+
- **Delete query**: O(1) with primary key
|
|
383
|
+
- **Cascade deletes**: O(m) where m = related records
|
|
384
|
+
- **Working memory remove**: O(1) hash delete
|
|
385
|
+
- **Total**: < 10ms for typical deletion
|
|
386
|
+
|
|
387
|
+
### Audit Log Growth
|
|
388
|
+
|
|
389
|
+
- **One log entry per deletion**: Minimal overhead
|
|
390
|
+
- **Log table indexed**: Fast queries by operation, robot_id, timestamp
|
|
391
|
+
- **Partitioning**: Can partition by timestamp if needed
|
|
392
|
+
|
|
393
|
+
### Storage Growth (Never-Forget)
|
|
394
|
+
|
|
395
|
+
- **Long-term memory**: Grows unbounded without cleanup
|
|
396
|
+
- **Typical growth**: ~100-1000 nodes per day (varies widely)
|
|
397
|
+
- **Storage**: ~1-10 KB per node (text + embedding)
|
|
398
|
+
- **Annual growth estimate**: ~365-3650 MB per year
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
## Design Decisions
|
|
403
|
+
|
|
404
|
+
### Decision: Confirmation Symbol (`:confirmed`) Instead of Boolean
|
|
405
|
+
|
|
406
|
+
**Rationale**:
|
|
407
|
+
|
|
408
|
+
- Boolean `confirm: true` is too easy to add casually
|
|
409
|
+
- Symbol `:confirmed` requires deliberate intent
|
|
410
|
+
- Harder to accidentally pass `true` vs `:confirmed`
|
|
411
|
+
|
|
412
|
+
**Alternative**: `confirm: true`
|
|
413
|
+
|
|
414
|
+
**Rejected**: Too casual, easy to misuse
|
|
415
|
+
|
|
416
|
+
**Alternative**: `confirm: "I am sure"`
|
|
417
|
+
|
|
418
|
+
**Rejected**: String matching is fragile
|
|
419
|
+
|
|
420
|
+
### Decision: Raise Error on Missing Confirmation
|
|
421
|
+
|
|
422
|
+
**Rationale**: Fail-safe default, loud failure prevents data loss
|
|
423
|
+
|
|
424
|
+
```ruby
|
|
425
|
+
htm.forget("key") # Raises ArgumentError
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
**Alternative**: Silently ignore (return false)
|
|
429
|
+
|
|
430
|
+
**Rejected**: Silent failures are dangerous
|
|
431
|
+
|
|
432
|
+
**Alternative**: Prompt user for confirmation
|
|
433
|
+
|
|
434
|
+
**Rejected**: Not appropriate for library code
|
|
435
|
+
|
|
436
|
+
### Decision: Log Before Delete (Not After)
|
|
437
|
+
|
|
438
|
+
**Rationale**: Avoid foreign key constraint violations
|
|
439
|
+
|
|
440
|
+
**Alternative**: Log after delete
|
|
441
|
+
|
|
442
|
+
**Rejected**: Foreign key violation if node_id referenced
|
|
443
|
+
|
|
444
|
+
**Alternative**: Allow NULL node_id in logs
|
|
445
|
+
|
|
446
|
+
**Rejected**: Lose referential integrity
|
|
447
|
+
|
|
448
|
+
### Decision: Eviction Preserves in Long-Term Memory
|
|
449
|
+
|
|
450
|
+
**Rationale**: Core never-forget philosophy
|
|
451
|
+
|
|
452
|
+
**Alternative**: Eviction = deletion
|
|
453
|
+
|
|
454
|
+
**Rejected**: Violates never-forget principle
|
|
455
|
+
|
|
456
|
+
**Alternative**: Archive to separate table
|
|
457
|
+
|
|
458
|
+
**Deferred**: Can optimize with archival tables later
|
|
459
|
+
|
|
460
|
+
### Decision: No TTL (Time-To-Live) Feature
|
|
461
|
+
|
|
462
|
+
**Rationale**: Simplicity, never-forget philosophy
|
|
463
|
+
|
|
464
|
+
**Alternative**: Optional TTL per memory
|
|
465
|
+
|
|
466
|
+
**Deferred**: Can add later if needed
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
## Risks and Mitigations
|
|
471
|
+
|
|
472
|
+
### Risk: Unbounded Storage Growth
|
|
473
|
+
|
|
474
|
+
!!! warning "Risk"
|
|
475
|
+
Database grows indefinitely, storage costs increase
|
|
476
|
+
|
|
477
|
+
**Likelihood**: High (by design, never-forget)
|
|
478
|
+
|
|
479
|
+
**Impact**: Medium (storage costs, query slowdown)
|
|
480
|
+
|
|
481
|
+
**Mitigation**:
|
|
482
|
+
|
|
483
|
+
- Monitor database size
|
|
484
|
+
- Implement archival strategies (future)
|
|
485
|
+
- Document cleanup procedures
|
|
486
|
+
- Compression policies (TimescaleDB)
|
|
487
|
+
- User-driven cleanup with bulk delete utilities
|
|
488
|
+
|
|
489
|
+
### Risk: Accidental Deletion Despite Confirmation
|
|
490
|
+
|
|
491
|
+
!!! danger "Risk"
|
|
492
|
+
User confirms deletion by mistake
|
|
493
|
+
|
|
494
|
+
**Likelihood**: Low (confirmation is speed bump)
|
|
495
|
+
|
|
496
|
+
**Impact**: High (permanent data loss)
|
|
497
|
+
|
|
498
|
+
**Mitigation**:
|
|
499
|
+
|
|
500
|
+
- Audit log preserves what was deleted
|
|
501
|
+
- Future: "undo delete" within time window
|
|
502
|
+
- Future: "soft delete" with archival table
|
|
503
|
+
- Document deletion is permanent
|
|
504
|
+
|
|
505
|
+
### Risk: Performance Degradation
|
|
506
|
+
|
|
507
|
+
!!! info "Risk"
|
|
508
|
+
Large dataset slows down queries
|
|
509
|
+
|
|
510
|
+
**Likelihood**: Medium (depends on usage)
|
|
511
|
+
|
|
512
|
+
**Impact**: Medium (slower recall)
|
|
513
|
+
|
|
514
|
+
**Mitigation**:
|
|
515
|
+
|
|
516
|
+
- Indexes on key, robot_id, created_at, embedding
|
|
517
|
+
- TimescaleDB compression for old data
|
|
518
|
+
- Archival to separate table (future)
|
|
519
|
+
- Partitioning by time range
|
|
520
|
+
|
|
521
|
+
### Risk: Privacy Concerns
|
|
522
|
+
|
|
523
|
+
!!! danger "Risk"
|
|
524
|
+
Sensitive data persists indefinitely
|
|
525
|
+
|
|
526
|
+
**Likelihood**: Medium (users may store sensitive info)
|
|
527
|
+
|
|
528
|
+
**Impact**: High (privacy violation)
|
|
529
|
+
|
|
530
|
+
**Mitigation**:
|
|
531
|
+
|
|
532
|
+
- Document data retention clearly
|
|
533
|
+
- Provide secure deletion utilities
|
|
534
|
+
- Encryption at rest (PostgreSQL)
|
|
535
|
+
- User awareness of never-forget philosophy
|
|
536
|
+
|
|
537
|
+
---
|
|
538
|
+
|
|
539
|
+
## Future Enhancements
|
|
540
|
+
|
|
541
|
+
### Soft Delete (Archival)
|
|
542
|
+
|
|
543
|
+
```ruby
|
|
544
|
+
# Mark as deleted instead of hard delete
|
|
545
|
+
htm.archive("key_to_archive", confirm: :confirmed)
|
|
546
|
+
|
|
547
|
+
# Archived memories excluded from queries
|
|
548
|
+
# But recoverable if needed
|
|
549
|
+
htm.unarchive("key_to_archive")
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### Undo Delete (Time Window)
|
|
553
|
+
|
|
554
|
+
```ruby
|
|
555
|
+
# Soft delete with 30-day recovery window
|
|
556
|
+
htm.forget("key", confirm: :confirmed)
|
|
557
|
+
|
|
558
|
+
# Within 30 days: undo
|
|
559
|
+
htm.undo_forget("key")
|
|
560
|
+
|
|
561
|
+
# After 30 days: permanent deletion
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
### Retention Policies
|
|
565
|
+
|
|
566
|
+
```ruby
|
|
567
|
+
# Automatic archival based on age and importance
|
|
568
|
+
htm.configure_retention(
|
|
569
|
+
archive_after_days: 365,
|
|
570
|
+
min_importance: 5.0 # Don't archive high-importance
|
|
571
|
+
)
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
### Bulk Delete Utilities
|
|
575
|
+
|
|
576
|
+
```ruby
|
|
577
|
+
# Delete all nodes matching criteria
|
|
578
|
+
HTM::Cleanup.delete_by_tag("temporary", confirm: :confirmed)
|
|
579
|
+
HTM::Cleanup.delete_older_than(1.year.ago, confirm: :confirmed)
|
|
580
|
+
HTM::Cleanup.delete_by_robot("robot-123", confirm: :confirmed)
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
### Encryption for Sensitive Data
|
|
584
|
+
|
|
585
|
+
```ruby
|
|
586
|
+
# Encrypt sensitive memories
|
|
587
|
+
htm.add_node("api_key", sensitive_value,
|
|
588
|
+
encrypt: true,
|
|
589
|
+
importance: 10.0)
|
|
590
|
+
|
|
591
|
+
# Automatically encrypted in database
|
|
592
|
+
# Decrypted on retrieval
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
### Audit Log Analysis
|
|
596
|
+
|
|
597
|
+
```ruby
|
|
598
|
+
# Analyze deletion patterns
|
|
599
|
+
HTM::Analytics.deletion_report(timeframe: "last month")
|
|
600
|
+
|
|
601
|
+
# Who deletes the most?
|
|
602
|
+
# What types of memories are deleted?
|
|
603
|
+
# When are deletions happening?
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
---
|
|
607
|
+
|
|
608
|
+
## Alternatives Comparison
|
|
609
|
+
|
|
610
|
+
| Approach | Pros | Cons | Decision |
|
|
611
|
+
|----------|------|------|----------|
|
|
612
|
+
| **Never-Forget with Explicit Delete** | **Predictable, safe** | **Storage growth** | **ACCEPTED** |
|
|
613
|
+
| Automatic TTL | Automatic cleanup | Surprise deletions | Rejected |
|
|
614
|
+
| LRU with Deletion | Simple capacity management | Data loss | Rejected |
|
|
615
|
+
| No Deletion API | Simplest never-forget | No escape hatch | Rejected |
|
|
616
|
+
| Confirmation via Prompt | User-friendly | Not library-appropriate | Rejected |
|
|
617
|
+
| Soft Delete by Default | Recoverable | Complex, unclear | Deferred |
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
|
|
621
|
+
## References
|
|
622
|
+
|
|
623
|
+
- [Never Forget Principle](https://en.wikipedia.org/wiki/Persistence_(computer_science))
|
|
624
|
+
- [Audit Logging Best Practices](https://owasp.org/www-community/Audit_Logging)
|
|
625
|
+
- [Soft Deletion Pattern](https://en.wikipedia.org/wiki/Soft_deletion)
|
|
626
|
+
- [GDPR Right to Erasure](https://gdpr.eu/right-to-be-forgotten/)
|
|
627
|
+
- [Data Retention Policies](https://en.wikipedia.org/wiki/Data_retention)
|
|
628
|
+
- [ADR-002: Two-Tier Memory](002-two-tier-memory.md)
|
|
629
|
+
- [ADR-007: Eviction Strategy](007-eviction-strategy.md)
|
|
630
|
+
- [Long-Term Memory Guide](../../guides/long-term-memory.md)
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
## Review Notes
|
|
635
|
+
|
|
636
|
+
**Systems Architect**: Never-forget philosophy is core value proposition. Explicit deletion is correct.
|
|
637
|
+
|
|
638
|
+
**Security Specialist**: Document data retention clearly. Consider encryption for sensitive data. GDPR implications?
|
|
639
|
+
|
|
640
|
+
**Domain Expert**: Two-tier architecture enables never-forget without performance penalty. Smart design.
|
|
641
|
+
|
|
642
|
+
**Ruby Expert**: Symbol confirmation (`:confirmed`) is idiomatic Ruby. Better than boolean.
|
|
643
|
+
|
|
644
|
+
**AI Engineer**: Persistent memory is critical for LLM context. Automatic deletion would degrade performance.
|
|
645
|
+
|
|
646
|
+
**Performance Specialist**: Monitor storage growth. Plan for archival strategies. Compression will help.
|
|
647
|
+
|
|
648
|
+
**Database Architect**: Log-before-delete prevents foreign key violations. Consider partitioning for large datasets.
|