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.
Files changed (155) hide show
  1. checksums.yaml +7 -0
  2. data/.architecture/decisions/adrs/001-use-postgresql-timescaledb-storage.md +227 -0
  3. data/.architecture/decisions/adrs/002-two-tier-memory-architecture.md +322 -0
  4. data/.architecture/decisions/adrs/003-ollama-default-embedding-provider.md +339 -0
  5. data/.architecture/decisions/adrs/004-multi-robot-shared-memory-hive-mind.md +374 -0
  6. data/.architecture/decisions/adrs/005-rag-based-retrieval-with-hybrid-search.md +443 -0
  7. data/.architecture/decisions/adrs/006-context-assembly-strategies.md +444 -0
  8. data/.architecture/decisions/adrs/007-working-memory-eviction-strategy.md +461 -0
  9. data/.architecture/decisions/adrs/008-robot-identification-system.md +550 -0
  10. data/.architecture/decisions/adrs/009-never-forget-explicit-deletion-only.md +570 -0
  11. data/.architecture/decisions/adrs/010-redis-working-memory-rejected.md +323 -0
  12. data/.architecture/decisions/adrs/011-database-side-embedding-generation-with-pgai.md +585 -0
  13. data/.architecture/decisions/adrs/012-llm-driven-ontology-topic-extraction.md +583 -0
  14. data/.architecture/decisions/adrs/013-activerecord-orm-and-many-to-many-tagging.md +299 -0
  15. data/.architecture/decisions/adrs/014-client-side-embedding-generation-workflow.md +569 -0
  16. data/.architecture/decisions/adrs/015-hierarchical-tag-ontology-and-llm-extraction.md +701 -0
  17. data/.architecture/decisions/adrs/016-async-embedding-and-tag-generation.md +694 -0
  18. data/.architecture/members.yml +144 -0
  19. data/.architecture/reviews/2025-10-29-llm-configuration-and-async-processing-review.md +1137 -0
  20. data/.architecture/reviews/initial-system-analysis.md +330 -0
  21. data/.envrc +32 -0
  22. data/.irbrc +145 -0
  23. data/CHANGELOG.md +150 -0
  24. data/COMMITS.md +196 -0
  25. data/LICENSE +21 -0
  26. data/README.md +1347 -0
  27. data/Rakefile +51 -0
  28. data/SETUP.md +268 -0
  29. data/config/database.yml +67 -0
  30. data/db/migrate/20250101000001_enable_extensions.rb +14 -0
  31. data/db/migrate/20250101000002_create_robots.rb +14 -0
  32. data/db/migrate/20250101000003_create_nodes.rb +42 -0
  33. data/db/migrate/20250101000005_create_tags.rb +38 -0
  34. data/db/migrate/20250101000007_add_node_vector_indexes.rb +30 -0
  35. data/db/schema.sql +473 -0
  36. data/db/seed_data/README.md +100 -0
  37. data/db/seed_data/presidents.md +136 -0
  38. data/db/seed_data/states.md +151 -0
  39. data/db/seeds.rb +208 -0
  40. data/dbdoc/README.md +173 -0
  41. data/dbdoc/public.node_stats.md +48 -0
  42. data/dbdoc/public.node_stats.svg +41 -0
  43. data/dbdoc/public.node_tags.md +40 -0
  44. data/dbdoc/public.node_tags.svg +112 -0
  45. data/dbdoc/public.nodes.md +54 -0
  46. data/dbdoc/public.nodes.svg +118 -0
  47. data/dbdoc/public.nodes_tags.md +39 -0
  48. data/dbdoc/public.nodes_tags.svg +112 -0
  49. data/dbdoc/public.ontology_structure.md +48 -0
  50. data/dbdoc/public.ontology_structure.svg +38 -0
  51. data/dbdoc/public.operations_log.md +42 -0
  52. data/dbdoc/public.operations_log.svg +130 -0
  53. data/dbdoc/public.relationships.md +39 -0
  54. data/dbdoc/public.relationships.svg +41 -0
  55. data/dbdoc/public.robot_activity.md +46 -0
  56. data/dbdoc/public.robot_activity.svg +35 -0
  57. data/dbdoc/public.robots.md +35 -0
  58. data/dbdoc/public.robots.svg +90 -0
  59. data/dbdoc/public.schema_migrations.md +29 -0
  60. data/dbdoc/public.schema_migrations.svg +26 -0
  61. data/dbdoc/public.tags.md +35 -0
  62. data/dbdoc/public.tags.svg +60 -0
  63. data/dbdoc/public.topic_relationships.md +45 -0
  64. data/dbdoc/public.topic_relationships.svg +32 -0
  65. data/dbdoc/schema.json +1437 -0
  66. data/dbdoc/schema.svg +154 -0
  67. data/docs/api/database.md +806 -0
  68. data/docs/api/embedding-service.md +532 -0
  69. data/docs/api/htm.md +797 -0
  70. data/docs/api/index.md +259 -0
  71. data/docs/api/long-term-memory.md +1096 -0
  72. data/docs/api/working-memory.md +665 -0
  73. data/docs/architecture/adrs/001-postgresql-timescaledb.md +314 -0
  74. data/docs/architecture/adrs/002-two-tier-memory.md +411 -0
  75. data/docs/architecture/adrs/003-ollama-embeddings.md +421 -0
  76. data/docs/architecture/adrs/004-hive-mind.md +437 -0
  77. data/docs/architecture/adrs/005-rag-retrieval.md +531 -0
  78. data/docs/architecture/adrs/006-context-assembly.md +496 -0
  79. data/docs/architecture/adrs/007-eviction-strategy.md +645 -0
  80. data/docs/architecture/adrs/008-robot-identification.md +625 -0
  81. data/docs/architecture/adrs/009-never-forget.md +648 -0
  82. data/docs/architecture/adrs/010-redis-working-memory-rejected.md +323 -0
  83. data/docs/architecture/adrs/011-pgai-integration.md +494 -0
  84. data/docs/architecture/adrs/index.md +215 -0
  85. data/docs/architecture/hive-mind.md +736 -0
  86. data/docs/architecture/index.md +351 -0
  87. data/docs/architecture/overview.md +538 -0
  88. data/docs/architecture/two-tier-memory.md +873 -0
  89. data/docs/assets/css/custom.css +83 -0
  90. data/docs/assets/images/htm-core-components.svg +63 -0
  91. data/docs/assets/images/htm-database-schema.svg +93 -0
  92. data/docs/assets/images/htm-hive-mind-architecture.svg +125 -0
  93. data/docs/assets/images/htm-importance-scoring-framework.svg +83 -0
  94. data/docs/assets/images/htm-layered-architecture.svg +71 -0
  95. data/docs/assets/images/htm-long-term-memory-architecture.svg +115 -0
  96. data/docs/assets/images/htm-working-memory-architecture.svg +120 -0
  97. data/docs/assets/images/htm.jpg +0 -0
  98. data/docs/assets/images/htm_demo.gif +0 -0
  99. data/docs/assets/js/mathjax.js +18 -0
  100. data/docs/assets/videos/htm_video.mp4 +0 -0
  101. data/docs/database_rake_tasks.md +322 -0
  102. data/docs/development/contributing.md +787 -0
  103. data/docs/development/index.md +336 -0
  104. data/docs/development/schema.md +596 -0
  105. data/docs/development/setup.md +719 -0
  106. data/docs/development/testing.md +819 -0
  107. data/docs/guides/adding-memories.md +824 -0
  108. data/docs/guides/context-assembly.md +1009 -0
  109. data/docs/guides/getting-started.md +577 -0
  110. data/docs/guides/index.md +118 -0
  111. data/docs/guides/long-term-memory.md +941 -0
  112. data/docs/guides/multi-robot.md +866 -0
  113. data/docs/guides/recalling-memories.md +927 -0
  114. data/docs/guides/search-strategies.md +953 -0
  115. data/docs/guides/working-memory.md +717 -0
  116. data/docs/index.md +214 -0
  117. data/docs/installation.md +477 -0
  118. data/docs/multi_framework_support.md +519 -0
  119. data/docs/quick-start.md +655 -0
  120. data/docs/setup_local_database.md +302 -0
  121. data/docs/using_rake_tasks_in_your_app.md +383 -0
  122. data/examples/basic_usage.rb +93 -0
  123. data/examples/cli_app/README.md +317 -0
  124. data/examples/cli_app/htm_cli.rb +270 -0
  125. data/examples/custom_llm_configuration.rb +183 -0
  126. data/examples/example_app/Rakefile +71 -0
  127. data/examples/example_app/app.rb +206 -0
  128. data/examples/sinatra_app/Gemfile +21 -0
  129. data/examples/sinatra_app/app.rb +335 -0
  130. data/lib/htm/active_record_config.rb +113 -0
  131. data/lib/htm/configuration.rb +342 -0
  132. data/lib/htm/database.rb +594 -0
  133. data/lib/htm/embedding_service.rb +115 -0
  134. data/lib/htm/errors.rb +34 -0
  135. data/lib/htm/job_adapter.rb +154 -0
  136. data/lib/htm/jobs/generate_embedding_job.rb +65 -0
  137. data/lib/htm/jobs/generate_tags_job.rb +82 -0
  138. data/lib/htm/long_term_memory.rb +965 -0
  139. data/lib/htm/models/node.rb +109 -0
  140. data/lib/htm/models/node_tag.rb +33 -0
  141. data/lib/htm/models/robot.rb +52 -0
  142. data/lib/htm/models/tag.rb +76 -0
  143. data/lib/htm/railtie.rb +76 -0
  144. data/lib/htm/sinatra.rb +157 -0
  145. data/lib/htm/tag_service.rb +135 -0
  146. data/lib/htm/tasks.rb +38 -0
  147. data/lib/htm/version.rb +5 -0
  148. data/lib/htm/working_memory.rb +182 -0
  149. data/lib/htm.rb +400 -0
  150. data/lib/tasks/db.rake +19 -0
  151. data/lib/tasks/htm.rake +147 -0
  152. data/lib/tasks/jobs.rake +312 -0
  153. data/mkdocs.yml +190 -0
  154. data/scripts/install_local_database.sh +309 -0
  155. metadata +341 -0
@@ -0,0 +1,550 @@
1
+ # ADR-008: Robot Identification System
2
+
3
+ **Status**: Accepted
4
+
5
+ **Date**: 2025-10-25
6
+
7
+ **Decision Makers**: Dewayne VanHoozer, Claude (Anthropic)
8
+
9
+ ## Context
10
+
11
+ In the HTM hive mind architecture (ADR-004), multiple robots share a global memory database. Each robot needs a unique identity to:
12
+
13
+ - Attribute memories to their creator
14
+ - Track robot activity over time
15
+ - Enable queries like "which robot said this?"
16
+ - Debug conversation attribution
17
+ - Support future features (privacy, analytics, collaboration)
18
+
19
+ Identity requirements:
20
+
21
+ - **Uniqueness**: Must be globally unique (no collisions)
22
+ - **Persistence**: Should remain stable across sessions
23
+ - **Human-readable**: Developers need to identify robots easily
24
+ - **Automation**: Should auto-generate if not provided
25
+ - **Registration**: Track all robots using the system
26
+
27
+ Alternative identification schemes:
28
+
29
+ 1. **Auto-generated UUID only**: Unique but not human-readable
30
+ 2. **User-provided name only**: Readable but collision-prone
31
+ 3. **UUID + optional name**: Unique ID with optional readable name
32
+ 4. **Sequential ID**: Simple but requires coordination
33
+ 5. **Hostname + PID**: Automatic but not persistent across restarts
34
+
35
+ ## Decision
36
+
37
+ We will use a **dual-identifier system**: mandatory unique `robot_id` (UUID) + optional human-readable `robot_name`, with automatic generation if not provided.
38
+
39
+ ### Robot Identification Components
40
+
41
+ **1. Robot ID (`robot_id`)**
42
+
43
+ - **Type**: UUID v4 (RFC 4122)
44
+ - **Format**: `"f47ac10b-58cc-4372-a567-0e02b2c3d479"`
45
+ - **Generation**: `SecureRandom.uuid` if not provided
46
+ - **Persistence**: User-provided for stability, or auto-generated per session
47
+ - **Usage**: Primary key, foreign key references, attribution
48
+
49
+ **2. Robot Name (`robot_name`)**
50
+
51
+ - **Type**: String (optional, human-readable)
52
+ - **Format**: Any descriptive string (e.g., "Code Helper", "Research Assistant")
53
+ - **Generation**: `"robot_#{robot_id[0..7]}"` if not provided
54
+ - **Persistence**: Stored in database, updatable
55
+ - **Usage**: Display, debugging, user interfaces
56
+
57
+ ### Initialization
58
+
59
+ ```ruby
60
+ htm = HTM.new(
61
+ robot_id: "f47ac10b-58cc-4372-a567-0e02b2c3d479", # optional, auto-generated
62
+ robot_name: "Code Helper" # optional, descriptive
63
+ )
64
+
65
+ # Auto-generated example:
66
+ # robot_id: "3a7b2c4d-8e9f-4a5b-9c8d-7e6f5a4b3c2d"
67
+ # robot_name: "robot_3a7b2c4d"
68
+ ```
69
+
70
+ ### Robot Registry
71
+
72
+ **Database Table**:
73
+ ```sql
74
+ CREATE TABLE robots (
75
+ id TEXT PRIMARY KEY, -- robot_id (UUID)
76
+ name TEXT, -- robot_name (human-readable)
77
+ created_at TIMESTAMP DEFAULT NOW(),
78
+ last_active TIMESTAMP DEFAULT NOW(),
79
+ metadata JSONB -- future extensibility
80
+ );
81
+ ```
82
+
83
+ **Registration**:
84
+ - Automatic on first HTM initialization
85
+ - Upsert semantics: updates name and last_active if robot_id exists
86
+ - Activity tracking: `last_active` updated on every operation
87
+
88
+ ### Robot Attribution
89
+
90
+ Every memory node stores `robot_id`:
91
+ ```sql
92
+ CREATE TABLE nodes (
93
+ id SERIAL PRIMARY KEY,
94
+ key TEXT UNIQUE NOT NULL,
95
+ value TEXT NOT NULL,
96
+ robot_id TEXT NOT NULL REFERENCES robots(id), -- Attribution
97
+ ...
98
+ );
99
+ ```
100
+
101
+ ## Rationale
102
+
103
+ ### Why UUID + Name?
104
+
105
+ **UUID provides guarantees**:
106
+
107
+ - ✅ Globally unique (collision probability: ~10^-36)
108
+ - ✅ No coordination required (decentralized generation)
109
+ - ✅ Cryptographically random (unpredictable)
110
+ - ✅ Standard format (RFC 4122, widely supported)
111
+
112
+ **Name provides usability**:
113
+
114
+ - ✅ Human-readable in logs and debugging
115
+ - ✅ Meaningful for user-facing features
116
+ - ✅ Easy to remember ("Code Helper" vs UUID)
117
+ - ✅ Updatable without breaking references
118
+
119
+ **Combination is best**:
120
+
121
+ - UUID for database integrity
122
+ - Name for developer experience
123
+ - Auto-generation for convenience
124
+ - User control for persistence
125
+
126
+ ### Why Auto-Generate?
127
+
128
+ **Convenience**:
129
+
130
+ - Users don't need to manage UUIDs manually
131
+ - Works out-of-box with no configuration
132
+ - Still allows explicit robot_id for persistence
133
+
134
+ **Session vs Persistent Identity**:
135
+
136
+ - **Session identity**: Auto-generated UUID, ephemeral robot
137
+ - **Persistent identity**: User-provided UUID, stable across restarts
138
+
139
+ ```ruby
140
+ # Ephemeral robot (new UUID every session)
141
+ htm = HTM.new(robot_name: "Temp Helper")
142
+
143
+ # Persistent robot (same UUID across sessions)
144
+ ROBOT_ID = "f47ac10b-58cc-4372-a567-0e02b2c3d479"
145
+ htm = HTM.new(robot_id: ROBOT_ID, robot_name: "Persistent Helper")
146
+ ```
147
+
148
+ ### Why Register Robots?
149
+
150
+ **Activity tracking**:
151
+
152
+ - Know which robots are active
153
+ - Monitor robot usage patterns
154
+ - Identify inactive robots for cleanup
155
+
156
+ **Metadata extensibility**:
157
+
158
+ - Future: Robot roles, permissions, preferences
159
+ - Future: Robot groups/teams
160
+ - Future: Configuration per robot
161
+
162
+ **Debugging**:
163
+
164
+ - "Which robot created this memory?"
165
+ - "What has this robot been doing?"
166
+ - "When was this robot last active?"
167
+
168
+ ## Consequences
169
+
170
+ ### Positive
171
+
172
+ ✅ **Uniqueness guaranteed**: UUID collision-proof
173
+ ✅ **Human-readable**: Names easy to identify in logs
174
+ ✅ **Auto-generation**: Works without manual configuration
175
+ ✅ **Persistence option**: User can provide stable robot_id
176
+ ✅ **Attribution tracking**: Every memory linked to creator
177
+ ✅ **Activity monitoring**: Track robot usage over time
178
+ ✅ **Future-proof**: Metadata field for extensibility
179
+ ✅ **Standard format**: UUID is widely recognized
180
+
181
+ ### Negative
182
+
183
+ ❌ **Dual identifiers**: Two fields instead of one (complexity)
184
+ ❌ **Name collisions**: Names not unique (only IDs are)
185
+ ❌ **Manual persistence**: User must manage robot_id for stability
186
+ ❌ **No automatic migration**: Robot ID changes break historical attribution
187
+ ❌ **UUID verbosity**: UUIDs are long (36 characters)
188
+
189
+ ### Neutral
190
+
191
+ ➡️ **Session vs persistent**: User chooses ephemeral or stable identity
192
+ ➡️ **Name mutability**: Names can be updated, IDs cannot
193
+ ➡️ **Registry cleanup**: Inactive robots accumulate (manual cleanup needed)
194
+
195
+ ## Design Decisions
196
+
197
+ ### Decision: UUID v4 (Random) Instead of UUID v1 (Timestamp)
198
+ **Rationale
199
+
200
+ - No MAC address leakage (privacy)
201
+ - Cryptographically random (security)
202
+ - No clock synchronization needed
203
+
204
+ **Alternative**: UUID v1 (timestamp-based)
205
+ **Rejected**: MAC address exposure, clock sync issues
206
+
207
+ ### Decision: Optional robot_id, Mandatory robot_name
208
+ **Rationale**: Auto-generate both if not provided, allow user override
209
+
210
+ **Alternative**: Require user to provide robot_id
211
+ **Rejected**: Too much friction, poor DX
212
+
213
+ ### Decision: Auto-Generated Name Format
214
+ **Rationale**: `"robot_#{uuid[0..7]}"` provides:
215
+
216
+ - Uniqueness (first 8 chars usually unique)
217
+ - Traceability (prefix of robot_id)
218
+ - Consistency (predictable format)
219
+
220
+ **Alternative**: Random adjective + noun ("Happy Robot")
221
+ **Rejected**: Harder to correlate with robot_id
222
+
223
+ ### Decision: Upsert Semantics for Registration
224
+ **Rationale**: Allows robot_name updates, prevents duplicate registration errors
225
+
226
+ ```sql
227
+ INSERT INTO robots (id, name)
228
+ VALUES ($1, $2)
229
+ ON CONFLICT (id) DO UPDATE
230
+ SET name = $2, last_active = CURRENT_TIMESTAMP
231
+ ```
232
+
233
+ **Alternative**: Strict insert-only (error on duplicate)
234
+ **Rejected**: Prevents name updates, complicates initialization
235
+
236
+ ### Decision: JSONB Metadata Field
237
+ **Rationale**: Future extensibility without schema migrations
238
+
239
+ **Alternative**: Add columns as needed
240
+ **Deferred**: JSONB is flexible, add columns for indexed fields later
241
+
242
+ ## Use Cases
243
+
244
+ ### Use Case 1: Ephemeral Robot (Session Identity)
245
+ ```ruby
246
+ # New UUID generated every time
247
+ htm = HTM.new(robot_name: "Quick Helper")
248
+
249
+ # robot_id: auto-generated UUID
250
+ # robot_name: "Quick Helper"
251
+
252
+ # Next session: different robot_id, same name
253
+ # Memories attributed to different robot each time
254
+ ```
255
+
256
+ ### Use Case 2: Persistent Robot (Stable Identity)
257
+ ```ruby
258
+ # Store robot_id in config or environment
259
+ ROBOT_ID = ENV['ROBOT_ID'] || "f47ac10b-58cc-4372-a567-0e02b2c3d479"
260
+
261
+ htm = HTM.new(
262
+ robot_id: ROBOT_ID,
263
+ robot_name: "Code Helper"
264
+ )
265
+
266
+ # Same robot_id across sessions
267
+ # Memories consistently attributed to this robot
268
+ ```
269
+
270
+ ### Use Case 3: Multiple Robots in Same Process
271
+ ```ruby
272
+ # Research assistant
273
+ research_bot = HTM.new(
274
+ robot_id: "research-001",
275
+ robot_name: "Research Assistant"
276
+ )
277
+
278
+ # Code helper
279
+ code_bot = HTM.new(
280
+ robot_id: "code-001",
281
+ robot_name: "Code Helper"
282
+ )
283
+
284
+ # Each robot has own working memory
285
+ # Both share same long-term memory database
286
+ # Memories attributed to respective robots
287
+ ```
288
+
289
+ ### Use Case 4: Robot Activity Analysis
290
+ ```ruby
291
+ # Which robots have been active?
292
+ SELECT id, name, last_active
293
+ FROM robots
294
+ ORDER BY last_active DESC;
295
+
296
+ # Which robot contributed most memories?
297
+ SELECT robot_id, COUNT(*) as memory_count
298
+ FROM nodes
299
+ GROUP BY robot_id
300
+ ORDER BY memory_count DESC;
301
+
302
+ # What has "Code Helper" been doing?
303
+ SELECT operation, created_at, details
304
+ FROM operations_log
305
+ WHERE robot_id = (SELECT id FROM robots WHERE name = 'Code Helper')
306
+ ORDER BY created_at DESC
307
+ LIMIT 50;
308
+ ```
309
+
310
+ ### Use Case 5: Conversation Attribution
311
+ ```ruby
312
+ # Which robot discussed PostgreSQL?
313
+ breakdown = htm.which_robot_said("PostgreSQL")
314
+ # => { "f47ac10b-..." => 15, "3a7b2c4d-..." => 8 }
315
+
316
+ # Get robot names
317
+ robot_names = breakdown.keys.map do |robot_id|
318
+ db.query("SELECT name FROM robots WHERE id = $1", [robot_id]).first
319
+ end
320
+ ```
321
+
322
+ ## Robot Identity Lifecycle
323
+
324
+ ### 1. Creation
325
+ ```ruby
326
+ htm = HTM.new(robot_id: uuid, robot_name: name)
327
+ ```
328
+
329
+ ### 2. Registration
330
+ ```sql
331
+ INSERT INTO robots (id, name, created_at, last_active)
332
+ VALUES (uuid, name, NOW(), NOW())
333
+ ON CONFLICT (id) DO UPDATE SET name = name, last_active = NOW()
334
+ ```
335
+
336
+ ### 3. Activity Tracking
337
+ ```ruby
338
+ # On every HTM operation (add_node, recall, forget, retrieve)
339
+ @long_term_memory.update_robot_activity(@robot_id)
340
+ ```
341
+
342
+ ```sql
343
+ UPDATE robots
344
+ SET last_active = CURRENT_TIMESTAMP
345
+ WHERE id = robot_id
346
+ ```
347
+
348
+ ### 4. Attribution
349
+ ```ruby
350
+ # Every node stores robot_id
351
+ node_id = @long_term_memory.add(
352
+ key: key,
353
+ value: value,
354
+ robot_id: @robot_id, # Attribution
355
+ ...
356
+ )
357
+ ```
358
+
359
+ ### 5. Querying
360
+ ```ruby
361
+ # Find memories by robot
362
+ SELECT * FROM nodes WHERE robot_id = 'f47ac10b-...'
363
+
364
+ # Find robot by name
365
+ SELECT * FROM robots WHERE name = 'Code Helper'
366
+ ```
367
+
368
+ ### 6. Cleanup (Manual)
369
+ ```sql
370
+ -- Find inactive robots
371
+ SELECT * FROM robots WHERE last_active < NOW() - INTERVAL '30 days';
372
+
373
+ -- Delete robot and all its memories (use with caution!)
374
+ DELETE FROM nodes WHERE robot_id = 'f47ac10b-...';
375
+ DELETE FROM robots WHERE id = 'f47ac10b-...';
376
+ ```
377
+
378
+ ## Performance Characteristics
379
+
380
+ ### UUID Generation
381
+
382
+ - **Time**: < 1ms (SecureRandom.uuid)
383
+ - **Collision probability**: ~10^-36 for v4 UUID
384
+ - **Entropy**: 122 random bits
385
+
386
+ ### Robot Registration
387
+
388
+ - **Upsert query**: < 5ms
389
+ - **Index**: Primary key on `robots.id`
390
+ - **Frequency**: Once per HTM initialization
391
+
392
+ ### Activity Tracking
393
+
394
+ - **Update query**: < 2ms
395
+ - **Frequency**: Every HTM operation
396
+ - **Index**: Primary key on `robots.id`
397
+
398
+ ### Attribution Queries
399
+
400
+ - **Foreign key join**: O(log n) with index
401
+ - **Index**: `nodes.robot_id` indexed as foreign key
402
+
403
+ ## Risks and Mitigations
404
+
405
+ ### Risk: Robot ID Changes Break Attribution
406
+
407
+ - **Risk**: User changes robot_id, breaks historical attribution
408
+ - **Likelihood**: Low (user must explicitly change)
409
+ - **Impact**: High (attribution lost)
410
+ - **Mitigation**:
411
+ - Document robot_id persistence clearly
412
+ - Recommend storing robot_id in config
413
+ - Consider robot_id migration tool (future)
414
+
415
+ ### Risk: Name Collisions
416
+
417
+ - **Risk**: Multiple robots with same name
418
+ - **Likelihood**: Medium (names not enforced unique)
419
+ - **Impact**: Low (IDs are unique, names just for display)
420
+ - **Mitigation**:
421
+ - Document that names are not unique
422
+ - Use robot_id for queries, name for display
423
+ - Consider unique constraint on name (future)
424
+
425
+ ### Risk: Robot Registry Growth
426
+
427
+ - **Risk**: Inactive robots accumulate indefinitely
428
+ - **Likelihood**: High (no automatic cleanup)
429
+ - **Impact**: Low (storage, query slowdown)
430
+ - **Mitigation**:
431
+ - Document cleanup procedures
432
+ - Provide cleanup utilities (future)
433
+ - Monitor robot registry size
434
+
435
+ ### Risk: UUID Verbosity
436
+
437
+ - **Risk**: UUIDs are long (36 chars) in logs
438
+ - **Likelihood**: High (by design)
439
+ - **Impact**: Low (readability in logs)
440
+ - **Mitigation**:
441
+ - Use robot_name for logging
442
+ - Truncate UUID for display: `robot_id[0..7]`
443
+ - Full UUID available for debugging
444
+
445
+ ## Future Enhancements
446
+
447
+ ### Robot Groups/Teams
448
+ ```ruby
449
+ # Assign robots to teams
450
+ robot_team = db.exec("INSERT INTO robot_teams (robot_id, team_name) VALUES ($1, $2)",
451
+ [robot_id, "coding-team"])
452
+
453
+ # Query by team
454
+ memories = htm.recall(robot_team: "coding-team", topic: "APIs")
455
+ ```
456
+
457
+ ### Robot Permissions
458
+ ```ruby
459
+ # Role-based access control
460
+ robot_role = db.exec("INSERT INTO robot_roles (robot_id, role) VALUES ($1, $2)",
461
+ [robot_id, "admin"])
462
+
463
+ # Restrict operations by role
464
+ htm.forget(key, confirm: :confirmed) # Requires admin role
465
+ ```
466
+
467
+ ### Robot Configuration
468
+ ```ruby
469
+ # Per-robot settings
470
+ htm = HTM.new(
471
+ robot_id: uuid,
472
+ robot_name: name,
473
+ robot_config: {
474
+ embedding_model: "custom-model",
475
+ working_memory_size: 256_000,
476
+ preferences: { language: "en" }
477
+ }
478
+ )
479
+ ```
480
+
481
+ ### Robot Migration Tool
482
+ ```ruby
483
+ # Migrate memories from old robot_id to new one
484
+ HTM::Migration.migrate_robot(
485
+ from: "old-robot-id",
486
+ to: "new-robot-id"
487
+ )
488
+
489
+ # Updates all nodes.robot_id references
490
+ # Merges robot registry entries
491
+ ```
492
+
493
+ ### Short Robot IDs
494
+ ```ruby
495
+ # Generate shorter IDs (like GitHub: 7 chars)
496
+ short_id = SecureRandom.hex(4) # "3a7b2c4d"
497
+
498
+ htm = HTM.new(
499
+ robot_id: short_id,
500
+ robot_name: "Helper"
501
+ )
502
+
503
+ # Trade-off: Lower collision resistance, better readability
504
+ ```
505
+
506
+ ## Alternatives Considered
507
+
508
+ ### Sequential Integer IDs
509
+ **Pros**: Short, simple, sortable
510
+ **Cons**: Requires centralized coordination, not globally unique
511
+ **Decision**: ❌ Rejected - coordination complexity, collision risk
512
+
513
+ ### Hostname + PID
514
+ **Pros**: Automatic, no manual generation
515
+ **Cons**: Not persistent across restarts, hostname collisions
516
+ **Decision**: ❌ Rejected - not persistent, poor UX
517
+
518
+ ### User-Provided Name Only
519
+ **Pros**: Simple, human-readable
520
+ **Cons**: Collision-prone, not unique
521
+ **Decision**: ❌ Rejected - uniqueness essential for attribution
522
+
523
+ ### UUID Only (No Name)
524
+ **Pros**: Simple, guaranteed unique
525
+ **Cons**: Not human-readable, poor DX
526
+ **Decision**: ❌ Rejected - readability matters for debugging
527
+
528
+ ### ULID (Universally Unique Lexicographically Sortable ID)
529
+ **Pros**: Sortable, timestamp-embedded, shorter encoding
530
+ **Cons**: Less standard than UUID, timestamp leakage
531
+ **Decision**: 🔄 Deferred - consider for v2 if sorting needed
532
+
533
+ ## References
534
+
535
+ - [RFC 4122: UUID Specification](https://tools.ietf.org/html/rfc4122)
536
+ - [UUID v4 (Random)](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random))
537
+ - [ULID Specification](https://github.com/ulid/spec)
538
+ - [Robot Registry Pattern](https://martinfowler.com/eaaCatalog/registry.html)
539
+
540
+ ## Review Notes
541
+
542
+ **Systems Architect**: ✅ UUID + name is the right balance. Consider ULID for future versions.
543
+
544
+ **Database Architect**: ✅ Foreign key on robot_id is correct. Index on `nodes.robot_id` for attribution queries.
545
+
546
+ **Ruby Expert**: ✅ SecureRandom.uuid is standard. Consider `robot_id: SecureRandom.uuid` as default parameter.
547
+
548
+ **Security Specialist**: ✅ UUID v4 is cryptographically secure. No MAC address leakage.
549
+
550
+ **Domain Expert**: ✅ Auto-generation + manual override gives flexibility. Document persistence clearly.