htm 0.0.11 → 0.0.14

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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/.dictate.toml +46 -0
  3. data/.envrc +2 -0
  4. data/CHANGELOG.md +52 -2
  5. data/README.md +79 -0
  6. data/Rakefile +14 -2
  7. data/bin/htm_mcp.rb +94 -0
  8. data/config/database.yml +20 -13
  9. data/db/migrate/00010_add_soft_delete_to_associations.rb +29 -0
  10. data/db/migrate/00011_add_performance_indexes.rb +21 -0
  11. data/db/migrate/00012_add_tags_trigram_index.rb +18 -0
  12. data/db/migrate/00013_enable_lz4_compression.rb +43 -0
  13. data/db/schema.sql +49 -92
  14. data/docs/api/index.md +1 -1
  15. data/docs/api/yard/HTM.md +2 -4
  16. data/docs/architecture/index.md +1 -1
  17. data/docs/development/index.md +1 -1
  18. data/docs/getting-started/index.md +1 -1
  19. data/docs/guides/index.md +1 -1
  20. data/docs/images/telemetry-architecture.svg +153 -0
  21. data/docs/telemetry.md +391 -0
  22. data/examples/README.md +46 -1
  23. data/examples/cli_app/README.md +1 -1
  24. data/examples/cli_app/htm_cli.rb +1 -1
  25. data/examples/sinatra_app/app.rb +1 -1
  26. data/examples/telemetry/README.md +147 -0
  27. data/examples/telemetry/SETUP_README.md +169 -0
  28. data/examples/telemetry/demo.rb +498 -0
  29. data/examples/telemetry/grafana/dashboards/htm-metrics.json +457 -0
  30. data/lib/htm/configuration.rb +261 -70
  31. data/lib/htm/database.rb +46 -22
  32. data/lib/htm/embedding_service.rb +24 -14
  33. data/lib/htm/errors.rb +15 -1
  34. data/lib/htm/jobs/generate_embedding_job.rb +19 -0
  35. data/lib/htm/jobs/generate_propositions_job.rb +103 -0
  36. data/lib/htm/jobs/generate_tags_job.rb +24 -0
  37. data/lib/htm/loaders/markdown_chunker.rb +79 -0
  38. data/lib/htm/loaders/markdown_loader.rb +41 -15
  39. data/lib/htm/long_term_memory/fulltext_search.rb +138 -0
  40. data/lib/htm/long_term_memory/hybrid_search.rb +324 -0
  41. data/lib/htm/long_term_memory/node_operations.rb +209 -0
  42. data/lib/htm/long_term_memory/relevance_scorer.rb +355 -0
  43. data/lib/htm/long_term_memory/robot_operations.rb +34 -0
  44. data/lib/htm/long_term_memory/tag_operations.rb +428 -0
  45. data/lib/htm/long_term_memory/vector_search.rb +109 -0
  46. data/lib/htm/long_term_memory.rb +51 -1153
  47. data/lib/htm/models/node.rb +35 -2
  48. data/lib/htm/models/node_tag.rb +31 -0
  49. data/lib/htm/models/robot_node.rb +31 -0
  50. data/lib/htm/models/tag.rb +44 -0
  51. data/lib/htm/proposition_service.rb +169 -0
  52. data/lib/htm/query_cache.rb +214 -0
  53. data/lib/htm/sql_builder.rb +178 -0
  54. data/lib/htm/tag_service.rb +16 -6
  55. data/lib/htm/tasks.rb +8 -2
  56. data/lib/htm/telemetry.rb +224 -0
  57. data/lib/htm/version.rb +1 -1
  58. data/lib/htm.rb +64 -3
  59. data/lib/tasks/doc.rake +1 -1
  60. data/lib/tasks/htm.rake +259 -13
  61. data/mkdocs.yml +96 -96
  62. metadata +42 -16
  63. data/.aigcm_msg +0 -1
  64. data/.claude/settings.local.json +0 -95
  65. data/CLAUDE.md +0 -603
  66. data/examples/cli_app/temp.log +0 -93
  67. data/lib/htm/loaders/paragraph_chunker.rb +0 -112
  68. data/notes/ARCHITECTURE_REVIEW.md +0 -1167
  69. data/notes/IMPLEMENTATION_SUMMARY.md +0 -606
  70. data/notes/MULTI_FRAMEWORK_IMPLEMENTATION.md +0 -451
  71. data/notes/next_steps.md +0 -100
  72. data/notes/plan.md +0 -627
  73. data/notes/tag_ontology_enhancement_ideas.md +0 -222
  74. data/notes/timescaledb_removal_summary.md +0 -200
data/db/schema.sql CHANGED
@@ -38,6 +38,7 @@ CREATE TABLE public.file_sources (
38
38
  created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
39
39
  updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP
40
40
  );
41
+ ALTER TABLE ONLY public.file_sources ALTER COLUMN frontmatter SET COMPRESSION lz4;
41
42
 
42
43
  --
43
44
  -- Name: TABLE file_sources; Type: COMMENT; Schema: public; Owner: -
@@ -106,7 +107,8 @@ CREATE TABLE public.node_tags (
106
107
  id bigint NOT NULL,
107
108
  node_id bigint NOT NULL,
108
109
  tag_id bigint NOT NULL,
109
- created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP
110
+ created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
111
+ deleted_at timestamp(6) without time zone
110
112
  );
111
113
 
112
114
  --
@@ -171,6 +173,8 @@ CREATE TABLE public.nodes (
171
173
  metadata jsonb DEFAULT '{}'::jsonb NOT NULL,
172
174
  CONSTRAINT check_embedding_dimension CHECK (((embedding_dimension IS NULL) OR ((embedding_dimension > 0) AND (embedding_dimension <= 2000))))
173
175
  );
176
+ ALTER TABLE ONLY public.nodes ALTER COLUMN content SET COMPRESSION lz4;
177
+ ALTER TABLE ONLY public.nodes ALTER COLUMN metadata SET COMPRESSION lz4;
174
178
 
175
179
  --
176
180
  -- Name: TABLE nodes; Type: COMMENT; Schema: public; Owner: -
@@ -285,7 +289,9 @@ CREATE TABLE public.robot_nodes (
285
289
  last_remembered_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
286
290
  remember_count integer DEFAULT 1 NOT NULL,
287
291
  created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
288
- updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP
292
+ updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
293
+ working_memory boolean DEFAULT false NOT NULL,
294
+ deleted_at timestamp(6) without time zone
289
295
  );
290
296
 
291
297
  --
@@ -324,6 +330,12 @@ COMMENT ON COLUMN public.robot_nodes.last_remembered_at IS 'When this robot last
324
330
 
325
331
  COMMENT ON COLUMN public.robot_nodes.remember_count IS 'Number of times this robot has tried to remember this content';
326
332
 
333
+ --
334
+ -- Name: COLUMN robot_nodes.working_memory; Type: COMMENT; Schema: public; Owner: -
335
+ --
336
+
337
+ COMMENT ON COLUMN public.robot_nodes.working_memory IS 'True if this node is currently in the robot working memory';
338
+
327
339
  --
328
340
  -- Name: robot_nodes_id_seq; Type: SEQUENCE; Schema: public; Owner: -
329
341
  --
@@ -408,7 +420,8 @@ CREATE TABLE public.schema_migrations (
408
420
  CREATE TABLE public.tags (
409
421
  id bigint NOT NULL,
410
422
  name text NOT NULL,
411
- created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP
423
+ created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
424
+ deleted_at timestamp(6) without time zone
412
425
  );
413
426
 
414
427
  --
@@ -446,65 +459,6 @@ CREATE SEQUENCE public.tags_id_seq
446
459
 
447
460
  ALTER SEQUENCE public.tags_id_seq OWNED BY public.tags.id;
448
461
 
449
- --
450
- -- Name: working_memories; Type: TABLE; Schema: public; Owner: -
451
- --
452
-
453
- CREATE TABLE public.working_memories (
454
- id bigint NOT NULL,
455
- robot_id bigint NOT NULL,
456
- node_id bigint NOT NULL,
457
- added_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
458
- token_count integer
459
- );
460
-
461
- --
462
- -- Name: TABLE working_memories; Type: COMMENT; Schema: public; Owner: -
463
- --
464
-
465
- COMMENT ON TABLE public.working_memories IS 'Per-robot working memory state (optional persistence)';
466
-
467
- --
468
- -- Name: COLUMN working_memories.robot_id; Type: COMMENT; Schema: public; Owner: -
469
- --
470
-
471
- COMMENT ON COLUMN public.working_memories.robot_id IS 'Robot whose working memory this belongs to';
472
-
473
- --
474
- -- Name: COLUMN working_memories.node_id; Type: COMMENT; Schema: public; Owner: -
475
- --
476
-
477
- COMMENT ON COLUMN public.working_memories.node_id IS 'Node currently in working memory';
478
-
479
- --
480
- -- Name: COLUMN working_memories.added_at; Type: COMMENT; Schema: public; Owner: -
481
- --
482
-
483
- COMMENT ON COLUMN public.working_memories.added_at IS 'When node was added to working memory';
484
-
485
- --
486
- -- Name: COLUMN working_memories.token_count; Type: COMMENT; Schema: public; Owner: -
487
- --
488
-
489
- COMMENT ON COLUMN public.working_memories.token_count IS 'Cached token count for budget tracking';
490
-
491
- --
492
- -- Name: working_memories_id_seq; Type: SEQUENCE; Schema: public; Owner: -
493
- --
494
-
495
- CREATE SEQUENCE public.working_memories_id_seq
496
- START WITH 1
497
- INCREMENT BY 1
498
- NO MINVALUE
499
- NO MAXVALUE
500
- CACHE 1;
501
-
502
- --
503
- -- Name: working_memories_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
504
- --
505
-
506
- ALTER SEQUENCE public.working_memories_id_seq OWNED BY public.working_memories.id;
507
-
508
462
  --
509
463
  -- Name: file_sources id; Type: DEFAULT; Schema: public; Owner: -
510
464
  --
@@ -541,12 +495,6 @@ ALTER TABLE ONLY public.robots ALTER COLUMN id SET DEFAULT nextval('public.robot
541
495
 
542
496
  ALTER TABLE ONLY public.tags ALTER COLUMN id SET DEFAULT nextval('public.tags_id_seq'::regclass);
543
497
 
544
- --
545
- -- Name: working_memories id; Type: DEFAULT; Schema: public; Owner: -
546
- --
547
-
548
- ALTER TABLE ONLY public.working_memories ALTER COLUMN id SET DEFAULT nextval('public.working_memories_id_seq'::regclass);
549
-
550
498
  --
551
499
  -- Name: file_sources file_sources_pkey; Type: CONSTRAINT; Schema: public; Owner: -
552
500
  --
@@ -596,13 +544,6 @@ ALTER TABLE ONLY public.schema_migrations
596
544
  ALTER TABLE ONLY public.tags
597
545
  ADD CONSTRAINT tags_pkey PRIMARY KEY (id);
598
546
 
599
- --
600
- -- Name: working_memories working_memories_pkey; Type: CONSTRAINT; Schema: public; Owner: -
601
- --
602
-
603
- ALTER TABLE ONLY public.working_memories
604
- ADD CONSTRAINT working_memories_pkey PRIMARY KEY (id);
605
-
606
547
  --
607
548
  -- Name: idx_file_sources_hash; Type: INDEX; Schema: public; Owner: -
608
549
  --
@@ -645,6 +586,24 @@ CREATE UNIQUE INDEX idx_node_tags_unique ON public.node_tags USING btree (node_i
645
586
 
646
587
  CREATE INDEX idx_nodes_access_count ON public.nodes USING btree (access_count);
647
588
 
589
+ --
590
+ -- Name: idx_nodes_active; Type: INDEX; Schema: public; Owner: -
591
+ --
592
+
593
+ CREATE INDEX idx_nodes_active ON public.nodes USING btree (id) WHERE (deleted_at IS NULL);
594
+
595
+ --
596
+ -- Name: INDEX idx_nodes_active; Type: COMMENT; Schema: public; Owner: -
597
+ --
598
+
599
+ COMMENT ON INDEX public.idx_nodes_active IS 'Partial index for active (non-deleted) node queries';
600
+
601
+ --
602
+ -- Name: idx_nodes_active_with_embedding; Type: INDEX; Schema: public; Owner: -
603
+ --
604
+
605
+ CREATE INDEX idx_nodes_active_with_embedding ON public.nodes USING btree (id) WHERE ((deleted_at IS NULL) AND (embedding IS NOT NULL));
606
+
648
607
  --
649
608
  -- Name: idx_nodes_content_gin; Type: INDEX; Schema: public; Owner: -
650
609
  --
@@ -742,48 +701,46 @@ CREATE INDEX idx_robot_nodes_robot_id ON public.robot_nodes USING btree (robot_i
742
701
  CREATE UNIQUE INDEX idx_robot_nodes_unique ON public.robot_nodes USING btree (robot_id, node_id);
743
702
 
744
703
  --
745
- -- Name: idx_tags_name_pattern; Type: INDEX; Schema: public; Owner: -
704
+ -- Name: idx_robot_nodes_working_memory; Type: INDEX; Schema: public; Owner: -
746
705
  --
747
706
 
748
- CREATE INDEX idx_tags_name_pattern ON public.tags USING btree (name text_pattern_ops);
707
+ CREATE INDEX idx_robot_nodes_working_memory ON public.robot_nodes USING btree (robot_id, working_memory) WHERE (working_memory = true);
749
708
 
750
709
  --
751
- -- Name: idx_tags_name_unique; Type: INDEX; Schema: public; Owner: -
710
+ -- Name: idx_tags_name_pattern; Type: INDEX; Schema: public; Owner: -
752
711
  --
753
712
 
754
- CREATE UNIQUE INDEX idx_tags_name_unique ON public.tags USING btree (name);
713
+ CREATE INDEX idx_tags_name_pattern ON public.tags USING btree (name text_pattern_ops);
755
714
 
756
715
  --
757
- -- Name: idx_working_memories_node_id; Type: INDEX; Schema: public; Owner: -
716
+ -- Name: idx_tags_name_trgm; Type: INDEX; Schema: public; Owner: -
758
717
  --
759
718
 
760
- CREATE INDEX idx_working_memories_node_id ON public.working_memories USING btree (node_id);
719
+ CREATE INDEX idx_tags_name_trgm ON public.tags USING gin (name public.gin_trgm_ops);
761
720
 
762
721
  --
763
- -- Name: idx_working_memories_robot_id; Type: INDEX; Schema: public; Owner: -
722
+ -- Name: idx_tags_name_unique; Type: INDEX; Schema: public; Owner: -
764
723
  --
765
724
 
766
- CREATE INDEX idx_working_memories_robot_id ON public.working_memories USING btree (robot_id);
725
+ CREATE UNIQUE INDEX idx_tags_name_unique ON public.tags USING btree (name);
767
726
 
768
727
  --
769
- -- Name: idx_working_memories_unique; Type: INDEX; Schema: public; Owner: -
728
+ -- Name: index_node_tags_on_deleted_at; Type: INDEX; Schema: public; Owner: -
770
729
  --
771
730
 
772
- CREATE UNIQUE INDEX idx_working_memories_unique ON public.working_memories USING btree (robot_id, node_id);
731
+ CREATE INDEX index_node_tags_on_deleted_at ON public.node_tags USING btree (deleted_at);
773
732
 
774
733
  --
775
- -- Name: working_memories fk_rails_2c1d8b383c; Type: FK CONSTRAINT; Schema: public; Owner: -
734
+ -- Name: index_robot_nodes_on_deleted_at; Type: INDEX; Schema: public; Owner: -
776
735
  --
777
736
 
778
- ALTER TABLE ONLY public.working_memories
779
- ADD CONSTRAINT fk_rails_2c1d8b383c FOREIGN KEY (node_id) REFERENCES public.nodes(id) ON DELETE CASCADE;
737
+ CREATE INDEX index_robot_nodes_on_deleted_at ON public.robot_nodes USING btree (deleted_at);
780
738
 
781
739
  --
782
- -- Name: working_memories fk_rails_4b7c3eb07b; Type: FK CONSTRAINT; Schema: public; Owner: -
740
+ -- Name: index_tags_on_deleted_at; Type: INDEX; Schema: public; Owner: -
783
741
  --
784
742
 
785
- ALTER TABLE ONLY public.working_memories
786
- ADD CONSTRAINT fk_rails_4b7c3eb07b FOREIGN KEY (robot_id) REFERENCES public.robots(id) ON DELETE CASCADE;
743
+ CREATE INDEX index_tags_on_deleted_at ON public.tags USING btree (deleted_at);
787
744
 
788
745
  --
789
746
  -- Name: nodes fk_rails_920ad16d08; Type: FK CONSTRAINT; Schema: public; Owner: -
@@ -824,4 +781,4 @@ ALTER TABLE ONLY public.robot_nodes
824
781
  -- PostgreSQL database dump complete
825
782
  --
826
783
 
827
- \unrestrict DUrF24Zrve4qSBwlDrJ4qAzzZhvhX5s2S57oHYVJ0ZPbaDC4ItMZ29Pv9oI3Q9d
784
+ \unrestrict bjkKIo8iBhvKUCAsIDDWdDnwALL0oxUsmZVbvgEad6ZmhcLmalGL4Ih7bfe9nlh
data/docs/api/index.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # API Reference
2
2
 
3
- Complete API documentation for HTM (Hierarchical Temporary Memory).
3
+ Complete API documentation for HTM (Hierarchical Temporal Memory).
4
4
 
5
5
  ## Overview
6
6
 
data/docs/api/yard/HTM.md CHANGED
@@ -2,7 +2,7 @@
2
2
  **Inherits:** Object
3
3
 
4
4
 
5
- HTM (Hierarchical Temporary Memory) error classes
5
+ HTM (Hierarchical Temporal Memory) error classes
6
6
 
7
7
  All HTM errors inherit from HTM::Error, allowing you to catch all HTM-related
8
8
  errors with a single rescue clause.
@@ -75,6 +75,4 @@ Reset configuration to defaults
75
75
  ## configuration[RW] {: #attribute-c-configuration }
76
76
  Get current configuration
77
77
 
78
- **`@return`** [HTM::Configuration]
79
-
80
-
78
+ **`@return`** [HTM::Configuration]
@@ -1,6 +1,6 @@
1
1
  # Architecture Overview
2
2
 
3
- HTM (Hierarchical Temporary Memory) implements a sophisticated two-tier memory system designed specifically for LLM-based applications ("robots"). This architecture enables robots to maintain long-term context across sessions while managing token budgets efficiently.
3
+ HTM (Hierarchical Temporal Memory) implements a sophisticated two-tier memory system designed specifically for LLM-based applications ("robots"). This architecture enables robots to maintain long-term context across sessions while managing token budgets efficiently.
4
4
 
5
5
  ## System Overview
6
6
 
@@ -4,7 +4,7 @@ Welcome to the HTM development documentation! This guide will help you contribut
4
4
 
5
5
  ## About HTM Development
6
6
 
7
- HTM (Hierarchical Temporary Memory) is an open-source Ruby gem that provides intelligent memory management for LLM-based applications. The project is built with modern Ruby practices, comprehensive testing, and a focus on developer experience.
7
+ HTM (Hierarchical Temporal Memory) is an open-source Ruby gem that provides intelligent memory management for LLM-based applications. The project is built with modern Ruby practices, comprehensive testing, and a focus on developer experience.
8
8
 
9
9
  ### Project Values
10
10
 
@@ -1,6 +1,6 @@
1
1
  # Getting Started
2
2
 
3
- Welcome to HTM (Hierarchical Temporary Memory)! This section will help you get up and running quickly.
3
+ Welcome to HTM (Hierarchical Temporal Memory)! This section will help you get up and running quickly.
4
4
 
5
5
  ## Overview
6
6
 
data/docs/guides/index.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # HTM User Guides
2
2
 
3
- Welcome to the HTM (Hierarchical Temporary Memory) user guide collection. These guides will help you understand and effectively use HTM for building intelligent LLM-based applications with persistent memory.
3
+ Welcome to the HTM (Hierarchical Temporal Memory) user guide collection. These guides will help you understand and effectively use HTM for building intelligent LLM-based applications with persistent memory.
4
4
 
5
5
  ## What is HTM?
6
6
 
@@ -0,0 +1,153 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 500" style="background: transparent;">
2
+ <defs>
3
+ <!-- Gradients for visual depth -->
4
+ <linearGradient id="appGradient" x1="0%" y1="0%" x2="0%" y2="100%">
5
+ <stop offset="0%" style="stop-color:#3b82f6;stop-opacity:0.9"/>
6
+ <stop offset="100%" style="stop-color:#1d4ed8;stop-opacity:0.9"/>
7
+ </linearGradient>
8
+ <linearGradient id="telemetryGradient" x1="0%" y1="0%" x2="0%" y2="100%">
9
+ <stop offset="0%" style="stop-color:#8b5cf6;stop-opacity:0.9"/>
10
+ <stop offset="100%" style="stop-color:#6d28d9;stop-opacity:0.9"/>
11
+ </linearGradient>
12
+ <linearGradient id="nullGradient" x1="0%" y1="0%" x2="0%" y2="100%">
13
+ <stop offset="0%" style="stop-color:#6b7280;stop-opacity:0.8"/>
14
+ <stop offset="100%" style="stop-color:#4b5563;stop-opacity:0.8"/>
15
+ </linearGradient>
16
+ <linearGradient id="sdkGradient" x1="0%" y1="0%" x2="0%" y2="100%">
17
+ <stop offset="0%" style="stop-color:#10b981;stop-opacity:0.9"/>
18
+ <stop offset="100%" style="stop-color:#059669;stop-opacity:0.9"/>
19
+ </linearGradient>
20
+ <linearGradient id="backendGradient" x1="0%" y1="0%" x2="0%" y2="100%">
21
+ <stop offset="0%" style="stop-color:#f59e0b;stop-opacity:0.9"/>
22
+ <stop offset="100%" style="stop-color:#d97706;stop-opacity:0.9"/>
23
+ </linearGradient>
24
+
25
+ <!-- Arrow marker -->
26
+ <marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
27
+ <polygon points="0 0, 10 3.5, 0 7" fill="#94a3b8"/>
28
+ </marker>
29
+ <marker id="arrowheadGreen" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
30
+ <polygon points="0 0, 10 3.5, 0 7" fill="#10b981"/>
31
+ </marker>
32
+ </defs>
33
+
34
+ <!-- HTM Application Container -->
35
+ <rect x="50" y="30" width="700" height="280" rx="12" ry="12"
36
+ fill="none" stroke="#3b82f6" stroke-width="2" stroke-dasharray="5,5"/>
37
+ <text x="400" y="55" text-anchor="middle" fill="#e2e8f0" font-family="system-ui, sans-serif" font-size="16" font-weight="600">
38
+ HTM Application
39
+ </text>
40
+
41
+ <!-- Job boxes at top -->
42
+ <rect x="80" y="75" width="180" height="50" rx="8" ry="8" fill="url(#appGradient)"/>
43
+ <text x="170" y="105" text-anchor="middle" fill="#ffffff" font-family="system-ui, sans-serif" font-size="13" font-weight="500">
44
+ GenerateEmbeddingJob
45
+ </text>
46
+
47
+ <rect x="310" y="75" width="180" height="50" rx="8" ry="8" fill="url(#appGradient)"/>
48
+ <text x="400" y="105" text-anchor="middle" fill="#ffffff" font-family="system-ui, sans-serif" font-size="13" font-weight="500">
49
+ GenerateTagsJob
50
+ </text>
51
+
52
+ <rect x="540" y="75" width="180" height="50" rx="8" ry="8" fill="url(#appGradient)"/>
53
+ <text x="630" y="105" text-anchor="middle" fill="#ffffff" font-family="system-ui, sans-serif" font-size="13" font-weight="500">
54
+ Search Methods
55
+ </text>
56
+
57
+ <!-- Arrows from jobs to telemetry -->
58
+ <line x1="170" y1="125" x2="170" y2="155" stroke="#94a3b8" stroke-width="2" marker-end="url(#arrowhead)"/>
59
+ <line x1="400" y1="125" x2="400" y2="155" stroke="#94a3b8" stroke-width="2" marker-end="url(#arrowhead)"/>
60
+ <line x1="630" y1="125" x2="630" y2="155" stroke="#94a3b8" stroke-width="2" marker-end="url(#arrowhead)"/>
61
+
62
+ <!-- Horizontal connector line -->
63
+ <line x1="170" y1="155" x2="630" y2="155" stroke="#94a3b8" stroke-width="2"/>
64
+ <line x1="400" y1="155" x2="400" y2="170" stroke="#94a3b8" stroke-width="2" marker-end="url(#arrowhead)"/>
65
+
66
+ <!-- HTM::Telemetry box -->
67
+ <rect x="280" y="175" width="240" height="45" rx="8" ry="8" fill="url(#telemetryGradient)"/>
68
+ <text x="400" y="203" text-anchor="middle" fill="#ffffff" font-family="system-ui, sans-serif" font-size="14" font-weight="600">
69
+ HTM::Telemetry
70
+ </text>
71
+
72
+ <!-- Three branches from telemetry -->
73
+ <line x1="400" y1="220" x2="400" y2="240" stroke="#94a3b8" stroke-width="2"/>
74
+
75
+ <!-- Branch lines -->
76
+ <line x1="150" y1="240" x2="650" y2="240" stroke="#94a3b8" stroke-width="2"/>
77
+ <line x1="150" y1="240" x2="150" y2="255" stroke="#94a3b8" stroke-width="2" marker-end="url(#arrowhead)"/>
78
+ <line x1="400" y1="240" x2="400" y2="255" stroke="#94a3b8" stroke-width="2" marker-end="url(#arrowhead)"/>
79
+ <line x1="650" y1="240" x2="650" y2="255" stroke="#94a3b8" stroke-width="2" marker-end="url(#arrowhead)"/>
80
+
81
+ <!-- Three meter options -->
82
+ <rect x="70" y="260" width="160" height="55" rx="8" ry="8" fill="url(#nullGradient)"/>
83
+ <text x="150" y="283" text-anchor="middle" fill="#ffffff" font-family="system-ui, sans-serif" font-size="12" font-weight="500">
84
+ NullMeter
85
+ </text>
86
+ <text x="150" y="300" text-anchor="middle" fill="#d1d5db" font-family="system-ui, sans-serif" font-size="10">
87
+ (when disabled)
88
+ </text>
89
+
90
+ <rect x="320" y="260" width="160" height="55" rx="8" ry="8" fill="url(#sdkGradient)"/>
91
+ <text x="400" y="283" text-anchor="middle" fill="#ffffff" font-family="system-ui, sans-serif" font-size="12" font-weight="500">
92
+ OpenTelemetry
93
+ </text>
94
+ <text x="400" y="300" text-anchor="middle" fill="#d1fae5" font-family="system-ui, sans-serif" font-size="10">
95
+ SDK Meter
96
+ </text>
97
+
98
+ <rect x="570" y="260" width="160" height="55" rx="8" ry="8" fill="url(#nullGradient)"/>
99
+ <text x="650" y="283" text-anchor="middle" fill="#ffffff" font-family="system-ui, sans-serif" font-size="12" font-weight="500">
100
+ NullMeter
101
+ </text>
102
+ <text x="650" y="300" text-anchor="middle" fill="#d1d5db" font-family="system-ui, sans-serif" font-size="10">
103
+ (SDK missing)
104
+ </text>
105
+
106
+ <!-- Arrows to outcomes -->
107
+ <line x1="150" y1="315" x2="150" y2="345" stroke="#6b7280" stroke-width="2" stroke-dasharray="4,4"/>
108
+ <line x1="400" y1="315" x2="400" y2="345" stroke="#10b981" stroke-width="2" marker-end="url(#arrowheadGreen)"/>
109
+ <line x1="650" y1="315" x2="650" y2="345" stroke="#6b7280" stroke-width="2" stroke-dasharray="4,4"/>
110
+
111
+ <!-- Outcome labels -->
112
+ <text x="150" y="365" text-anchor="middle" fill="#9ca3af" font-family="system-ui, sans-serif" font-size="12" font-style="italic">
113
+ No-op
114
+ </text>
115
+
116
+ <text x="400" y="365" text-anchor="middle" fill="#10b981" font-family="system-ui, sans-serif" font-size="12" font-weight="500">
117
+ OTLP Export
118
+ </text>
119
+
120
+ <text x="650" y="365" text-anchor="middle" fill="#9ca3af" font-family="system-ui, sans-serif" font-size="12" font-style="italic">
121
+ No-op
122
+ </text>
123
+
124
+ <!-- Arrow to backend -->
125
+ <line x1="400" y1="380" x2="400" y2="410" stroke="#10b981" stroke-width="2" marker-end="url(#arrowheadGreen)"/>
126
+
127
+ <!-- Backend box -->
128
+ <rect x="250" y="420" width="300" height="60" rx="10" ry="10" fill="url(#backendGradient)"/>
129
+ <text x="400" y="448" text-anchor="middle" fill="#ffffff" font-family="system-ui, sans-serif" font-size="14" font-weight="600">
130
+ Observability Backend
131
+ </text>
132
+ <text x="400" y="468" text-anchor="middle" fill="#fef3c7" font-family="system-ui, sans-serif" font-size="11">
133
+ (Jaeger, Datadog, Prometheus, etc.)
134
+ </text>
135
+
136
+ <!-- Legend -->
137
+ <rect x="600" y="380" width="140" height="80" rx="6" ry="6" fill="#1e293b" fill-opacity="0.7" stroke="#475569" stroke-width="1"/>
138
+ <text x="670" y="398" text-anchor="middle" fill="#94a3b8" font-family="system-ui, sans-serif" font-size="10" font-weight="600">
139
+ LEGEND
140
+ </text>
141
+ <line x1="615" y1="410" x2="645" y2="410" stroke="#10b981" stroke-width="2"/>
142
+ <text x="720" y="414" text-anchor="end" fill="#d1d5db" font-family="system-ui, sans-serif" font-size="10">
143
+ Active flow
144
+ </text>
145
+ <line x1="615" y1="430" x2="645" y2="430" stroke="#6b7280" stroke-width="2" stroke-dasharray="4,4"/>
146
+ <text x="720" y="434" text-anchor="end" fill="#d1d5db" font-family="system-ui, sans-serif" font-size="10">
147
+ Disabled path
148
+ </text>
149
+ <circle cx="630" cy="450" r="6" fill="url(#telemetryGradient)"/>
150
+ <text x="720" y="454" text-anchor="end" fill="#d1d5db" font-family="system-ui, sans-serif" font-size="10">
151
+ HTM component
152
+ </text>
153
+ </svg>