markdown_composer 0.7.0

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 (116) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +23 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +278 -0
  5. data/ROADMAP.md +80 -0
  6. data/docs/_md_composer_architecture.md +50 -0
  7. data/docs/_md_composer_cheatsheet.md +72 -0
  8. data/docs/_md_composer_concepts.md +64 -0
  9. data/docs/_md_composer_dev_guide.md +55 -0
  10. data/docs/_md_composer_getting_started.md +114 -0
  11. data/docs/_md_composer_readme.md +93 -0
  12. data/docs/_md_composer_user_guide.md +65 -0
  13. data/docs/ai/md_composer_ai_audit.md +35 -0
  14. data/docs/ai/md_composer_ai_canonical_docs.md +44 -0
  15. data/docs/ai/md_composer_ai_source_map.md +39 -0
  16. data/docs/compose/md_composer_compose_actions.md +338 -0
  17. data/docs/compose/md_composer_compose_anatomy.md +156 -0
  18. data/docs/compose/md_composer_compose_buffer.md +81 -0
  19. data/docs/compose/md_composer_compose_examples.md +31 -0
  20. data/docs/compose/md_composer_compose_include.md +136 -0
  21. data/docs/compose/md_composer_compose_select.md +198 -0
  22. data/docs/compose/md_composer_compose_sources.md +161 -0
  23. data/docs/compose/md_composer_compose_targets.md +194 -0
  24. data/docs/examples/md_composer_example_basic_compose.md +57 -0
  25. data/docs/examples/md_composer_example_buffer_target_actions.md +83 -0
  26. data/docs/examples/md_composer_example_fixtures.md +62 -0
  27. data/docs/examples/md_composer_example_html_output.md +50 -0
  28. data/docs/examples/md_composer_example_modify.md +77 -0
  29. data/docs/examples/md_composer_example_multi_row_compose.md +67 -0
  30. data/docs/examples/md_composer_example_ruby_plans.md +62 -0
  31. data/docs/examples/md_composer_example_structured_data.md +68 -0
  32. data/docs/examples/md_composer_example_transforms.md +68 -0
  33. data/docs/examples/md_composer_example_yaml_json_rows.md +56 -0
  34. data/docs/examples/md_composer_examples_readme.md +45 -0
  35. data/docs/examples/md_composer_runnable_examples.md +374 -0
  36. data/docs/examples/md_composer_source_ruby_dsl.md +88 -0
  37. data/docs/reference/md_composer_nested.md +170 -0
  38. data/docs/reference/md_composer_reference_api.md +71 -0
  39. data/docs/reference/md_composer_reference_capabilities.md +63 -0
  40. data/docs/reference/md_composer_reference_diagnostics.md +54 -0
  41. data/docs/reference/md_composer_reference_plan_schema.md +75 -0
  42. data/docs/reference/md_composer_reference_registries.md +63 -0
  43. data/docs/reference/md_composer_take.md +221 -0
  44. data/docs/reference/md_composer_unit_tokens.md +228 -0
  45. data/docs/reference/md_composer_where.md +227 -0
  46. data/docs/transform/md_composer_transform_anatomy.md +112 -0
  47. data/docs/transform/md_composer_transform_examples.md +30 -0
  48. data/docs/transform/md_composer_transform_modes.md +83 -0
  49. data/docs/transform/md_composer_transform_options.md +142 -0
  50. data/docs/transform/md_composer_transform_scope.md +97 -0
  51. data/docs/transform/md_composer_transform_transforms.md +99 -0
  52. data/examples/README.md +20 -0
  53. data/examples/advanced_composer.rb +207 -0
  54. data/examples/basic_compose.rb +24 -0
  55. data/examples/complex_composer.rb +235 -0
  56. data/examples/example_support.rb +18 -0
  57. data/examples/fixtures/current.md +179 -0
  58. data/examples/fixtures/faq.md +58 -0
  59. data/examples/fixtures/guide.md +62 -0
  60. data/examples/fixtures/site_intro.md +29 -0
  61. data/examples/fixtures/source.html +22 -0
  62. data/examples/html_input.rb +26 -0
  63. data/examples/output/advanced_composer.md +76 -0
  64. data/examples/output/basic_compose.md +25 -0
  65. data/examples/output/complex_composer.md +85 -0
  66. data/examples/output/html_input.md +4 -0
  67. data/examples/output/source_list_dsl.md +126 -0
  68. data/examples/output/standard_composer.md +46 -0
  69. data/examples/output/standard_sources_buffer.md +31 -0
  70. data/examples/output/yaml_plan.md +43 -0
  71. data/examples/plans/basic.yml +20 -0
  72. data/examples/source_list_dsl.rb +41 -0
  73. data/examples/standard_composer.rb +42 -0
  74. data/examples/standard_sources_buffer.rb +62 -0
  75. data/examples/yaml_plan.rb +17 -0
  76. data/lib/markdown_composer/capabilities.rb +223 -0
  77. data/lib/markdown_composer/composition_buffer.rb +378 -0
  78. data/lib/markdown_composer/data_path.rb +313 -0
  79. data/lib/markdown_composer/diagnostics.rb +63 -0
  80. data/lib/markdown_composer/document_index/html_parser.rb +84 -0
  81. data/lib/markdown_composer/document_index/markdown_parser.rb +338 -0
  82. data/lib/markdown_composer/document_index.rb +94 -0
  83. data/lib/markdown_composer/executor.rb +284 -0
  84. data/lib/markdown_composer/markdown_renderer.rb +105 -0
  85. data/lib/markdown_composer/plan.rb +436 -0
  86. data/lib/markdown_composer/plan_builder.rb +111 -0
  87. data/lib/markdown_composer/registries/action_entries.rb +26 -0
  88. data/lib/markdown_composer/registries/condition_entries.rb +58 -0
  89. data/lib/markdown_composer/registries/registry.rb +69 -0
  90. data/lib/markdown_composer/registries/source_entries.rb +18 -0
  91. data/lib/markdown_composer/registries/support_values.rb +23 -0
  92. data/lib/markdown_composer/registries/take_entries.rb +31 -0
  93. data/lib/markdown_composer/registries/take_registry.rb +18 -0
  94. data/lib/markdown_composer/registries/target_entries.rb +40 -0
  95. data/lib/markdown_composer/registries/unit_token_entries.rb +62 -0
  96. data/lib/markdown_composer/registries/where_registry.rb +84 -0
  97. data/lib/markdown_composer/registries.rb +46 -0
  98. data/lib/markdown_composer/result.rb +34 -0
  99. data/lib/markdown_composer/selection_resolver.rb +181 -0
  100. data/lib/markdown_composer/source.rb +57 -0
  101. data/lib/markdown_composer/source_list_builder.rb +47 -0
  102. data/lib/markdown_composer/take.rb +129 -0
  103. data/lib/markdown_composer/transform_options.rb +66 -0
  104. data/lib/markdown_composer/transform_runner/content_placement.rb +63 -0
  105. data/lib/markdown_composer/transform_runner/field_interpolator.rb +213 -0
  106. data/lib/markdown_composer/transform_runner/heading_numbering.rb +106 -0
  107. data/lib/markdown_composer/transform_runner/scope_resolver.rb +87 -0
  108. data/lib/markdown_composer/transform_runner.rb +264 -0
  109. data/lib/markdown_composer/transforms/default_entries.rb +31 -0
  110. data/lib/markdown_composer/transforms/registry.rb +11 -0
  111. data/lib/markdown_composer/validator.rb +378 -0
  112. data/lib/markdown_composer/value_object.rb +15 -0
  113. data/lib/markdown_composer/version.rb +5 -0
  114. data/lib/markdown_composer/where.rb +313 -0
  115. data/lib/markdown_composer.rb +114 -0
  116. metadata +260 -0
@@ -0,0 +1,207 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "markdown_composer"
4
+ require_relative "example_support"
5
+
6
+ root = File.expand_path(__dir__)
7
+
8
+ # A comprehensive Ruby DSL example:
9
+ # - runtime sources: current, explicit, inherited
10
+ # - row sources: inline, previous, buffer
11
+ # - actions: set, append, prepend, insert_before, insert_after, insert_between,
12
+ # replace, copy, move, modify, remove_buffer_target, transform_buffer_target
13
+ # - transforms: scoped text replacement, insertion, dedupe, link rewrite, levels
14
+ plan = MarkdownComposer.plan do
15
+ output :markdown
16
+
17
+ from :current
18
+ select 'h2_section where title:equals("Feature Matrix")'
19
+ include "heading_title"
20
+ include "paragraph[first:1]"
21
+ include "link[first:1]"
22
+ include "table[first:1]"
23
+ include "heading_3_section[position:1,2] { heading_title; paragraph[first:1]; code_block; table }"
24
+ set
25
+
26
+ from({
27
+ type: "inline",
28
+ markdown: "### Advanced Preface\n\nThis section is prepended first, then moved into a better reading position."
29
+ })
30
+ select "h3_section"
31
+ include "all"
32
+ prepend
33
+
34
+ from({ type: "inherited", key: "site_intro" })
35
+ select 'h2_section where title:equals("Welcome")'
36
+ include "heading_title"
37
+ include "paragraph[first:1]"
38
+ append
39
+
40
+ transform_buffer_target(
41
+ 'h2 where title:equals("Welcome")',
42
+ transforms: [
43
+ {
44
+ "transform" => "heading_levels",
45
+ "mode" => "demote",
46
+ "options" => {
47
+ "by" => 1
48
+ }
49
+ }
50
+ ]
51
+ )
52
+
53
+ from({ type: "explicit", key: "guide" })
54
+ select 'h2_section where title:equals("Validate")'
55
+ include "all"
56
+ append
57
+
58
+ from :previous
59
+ select 'h2_section where title:equals("Publish")'
60
+ include "all"
61
+ append
62
+
63
+ transform_buffer_target(
64
+ 'h2 where title:equals("Validate")',
65
+ transforms: [
66
+ {
67
+ "transform" => "heading_levels",
68
+ "mode" => "demote",
69
+ "options" => {
70
+ "by" => 1
71
+ }
72
+ },
73
+ {
74
+ "scope" => "heading_3",
75
+ "transform" => "replace_text",
76
+ "mode" => "word",
77
+ "options" => {
78
+ "from" => "Validate",
79
+ "to" => "Validation Snapshot"
80
+ }
81
+ }
82
+ ]
83
+ )
84
+
85
+ transform_buffer_target(
86
+ 'h2 where title:equals("Publish")',
87
+ transforms: [
88
+ {
89
+ "transform" => "heading_levels",
90
+ "mode" => "demote",
91
+ "options" => {
92
+ "by" => 1
93
+ }
94
+ },
95
+ {
96
+ "scope" => "heading_3",
97
+ "transform" => "replace_text",
98
+ "mode" => "word",
99
+ "options" => {
100
+ "from" => "Publish",
101
+ "to" => "Release Checklist"
102
+ }
103
+ }
104
+ ]
105
+ )
106
+
107
+ from({
108
+ type: "inline",
109
+ markdown: "### Release Note\n\nThis inserted note shows small inline Markdown inside a larger plan."
110
+ })
111
+ select "h3_section"
112
+ include "all"
113
+ insert_before 'h3_section where title:equals("Automation")'
114
+
115
+ from :current
116
+ select 'h3_section where title:equals("Reporting")'
117
+ include "heading_title"
118
+ include "paragraph[first:1]"
119
+ replace 'h3_section where title:equals("Automation")'
120
+
121
+ from({
122
+ type: "inline",
123
+ markdown: "### Support Note\n\nThis note is inserted between two existing composed sections."
124
+ })
125
+ select "h3_section"
126
+ include "all"
127
+ insert_between 'Between h3_section where title:equals("Release Note") and h3_section where title:equals("Reporting")'
128
+
129
+ from :current
130
+ select 'h3_section where title:equals("Monitoring")'
131
+ include "heading_title"
132
+ include "paragraph[first:1]"
133
+ insert_after 'h3_section where title:equals("Reporting")'
134
+
135
+ from :buffer
136
+ select 'h3_section where title:equals("Release Note")'
137
+ include "all"
138
+ copy "end"
139
+
140
+ from :buffer
141
+ select 'h3_section where title:equals("Dashboard")'
142
+ include "all"
143
+ modify "in_place", transforms: [
144
+ {
145
+ "scope" => "heading_3, paragraph",
146
+ "transform" => "replace_text",
147
+ "mode" => "literal",
148
+ "options" => {
149
+ "from" => "Dashboard",
150
+ "to" => "Dashboard Snapshot"
151
+ }
152
+ },
153
+ {
154
+ "scope" => "paragraph[first:1]",
155
+ "transform" => "insert_after",
156
+ "mode" => "insert",
157
+ "options" => {
158
+ "content" => "This paragraph was inserted by the modify action before final output transforms run.",
159
+ "as" => "paragraph"
160
+ }
161
+ }
162
+ ]
163
+
164
+ from :buffer
165
+ select 'h3_section where title:equals("Advanced Preface")'
166
+ include "all"
167
+ move 'after h2_section where title:equals("Feature Matrix")'
168
+
169
+ from({
170
+ type: "inline",
171
+ markdown: "### Cleanup Marker\n\nThis temporary marker exists only to demonstrate remove_buffer_target."
172
+ })
173
+ select "h3_section"
174
+ include "all"
175
+ append
176
+
177
+ from :buffer
178
+ select 'h3_section where title:equals("Cleanup Marker")'
179
+ remove_buffer_target
180
+
181
+ transform "output", "dedupe", "normalised_text"
182
+
183
+ transform "heading_2", "replace_text", "literal", {
184
+ "from" => "Feature Matrix",
185
+ "to" => "Advanced Composer Walkthrough"
186
+ }
187
+
188
+ transform "link[first:1]", "links", "rewrite_url", {
189
+ "from" => "/features/dashboard",
190
+ "to" => "https://example.test/features/dashboard"
191
+ }
192
+
193
+ transform "heading", "heading_levels", "promote", {
194
+ "by" => 1
195
+ }
196
+ end
197
+
198
+ result = MarkdownComposer.compose(
199
+ sources: MarkdownComposer.source_list do
200
+ current File.read(File.join(root, "fixtures/current.md"))
201
+ explicit :guide, File.read(File.join(root, "fixtures/guide.md"))
202
+ inherited :site_intro, File.read(File.join(root, "fixtures/site_intro.md"))
203
+ end,
204
+ plan: plan
205
+ )
206
+
207
+ ExampleSupport.write_output(root, "advanced_composer", result)
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "markdown_composer"
4
+ require_relative "example_support"
5
+
6
+ root = File.expand_path(__dir__)
7
+ current_markdown = File.read(File.join(root, "fixtures/current.md"))
8
+
9
+ # Select the first H2 section from the current source and emit it unchanged.
10
+ plan = MarkdownComposer.plan do
11
+ from :current
12
+ select "h2_section[first:1]"
13
+ include "all"
14
+ set
15
+ end
16
+
17
+ result = MarkdownComposer.compose(
18
+ sources: [
19
+ { key: "current", type: "current", markdown: current_markdown }
20
+ ],
21
+ plan: plan
22
+ )
23
+
24
+ ExampleSupport.write_output(root, "basic_compose", result)
@@ -0,0 +1,235 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "markdown_composer"
4
+ require_relative "example_support"
5
+
6
+ root = File.expand_path(__dir__)
7
+
8
+ # The complex example is intentionally broad but still readable.
9
+ # Sources live in the compose call at the bottom, so the plan stays focused.
10
+ plan = MarkdownComposer.plan do
11
+ output :markdown
12
+
13
+ # Start with a focused current-source feature section.
14
+ from :current
15
+ select 'h2_section where title:equals("Feature Matrix")'
16
+ include "heading_title"
17
+ include "paragraph[first:1]"
18
+ include "link[first:1]"
19
+ include "table[first:1]"
20
+ include "heading_3_section[position:1,2] { heading_title; paragraph[first:1]; code_block; table }"
21
+ set
22
+
23
+ # Prepend an inline section, then move it later to demonstrate both actions.
24
+ from({
25
+ type: "inline",
26
+ markdown: "### Complex Preface\n\nThis section is prepended first, then moved into the final reading order."
27
+ })
28
+ select "h3_section"
29
+ include "all"
30
+ prepend
31
+
32
+ # Append inherited site copy and demote it while it is still in the buffer.
33
+ from({ type: "inherited", key: "site_intro" })
34
+ select 'h2_section where title:equals("Welcome")'
35
+ include "heading_title"
36
+ include "paragraph[first:1]"
37
+ append
38
+
39
+ transform_buffer_target(
40
+ 'h2 where title:equals("Welcome")',
41
+ transforms: [
42
+ {
43
+ "transform" => "heading_levels",
44
+ "mode" => "demote",
45
+ "options" => { "by" => 1 }
46
+ }
47
+ ]
48
+ )
49
+
50
+ # Append explicit guide content, then use previous to keep working in guide.
51
+ from({ type: "explicit", key: "guide" })
52
+ select 'h2_section where title:equals("Validate")'
53
+ include "all"
54
+ append
55
+
56
+ from :previous
57
+ select 'h2_section where title:equals("Publish")'
58
+ include "all"
59
+ append
60
+
61
+ transform_buffer_target(
62
+ 'h2 where title:equals("Validate")',
63
+ transforms: [
64
+ {
65
+ "transform" => "heading_levels",
66
+ "mode" => "demote",
67
+ "options" => { "by" => 1 }
68
+ },
69
+ {
70
+ "scope" => "heading_3",
71
+ "transform" => "replace_text",
72
+ "mode" => "word",
73
+ "options" => { "from" => "Validate", "to" => "Validation Snapshot" }
74
+ }
75
+ ]
76
+ )
77
+
78
+ transform_buffer_target(
79
+ 'h2 where title:equals("Publish")',
80
+ transforms: [
81
+ {
82
+ "transform" => "heading_levels",
83
+ "mode" => "demote",
84
+ "options" => { "by" => 1 }
85
+ },
86
+ {
87
+ "scope" => "heading_3",
88
+ "transform" => "replace_text",
89
+ "mode" => "word",
90
+ "options" => { "from" => "Publish", "to" => "Release Checklist" }
91
+ }
92
+ ]
93
+ )
94
+
95
+ # Add an explicit FAQ section and keep only the useful summary pieces.
96
+ from({ type: "explicit", key: "faq" })
97
+ select 'h2_section where title:equals("What source types exist?")'
98
+ include "heading_title"
99
+ include "paragraph[first:1]"
100
+ append
101
+
102
+ transform_buffer_target(
103
+ 'h2 where title:equals("What source types exist?")',
104
+ transforms: [
105
+ {
106
+ "transform" => "heading_levels",
107
+ "mode" => "demote",
108
+ "options" => { "by" => 1 }
109
+ },
110
+ {
111
+ "scope" => "heading_3",
112
+ "transform" => "replace_text",
113
+ "mode" => "literal",
114
+ "options" => {
115
+ "from" => "What source types exist?",
116
+ "to" => "Source Type Notes"
117
+ }
118
+ }
119
+ ]
120
+ )
121
+
122
+ # Use inline source content with insert_before and insert_between.
123
+ from({
124
+ type: "inline",
125
+ markdown: "### Release Note\n\nThis inserted note shows small inline Markdown inside a larger plan."
126
+ })
127
+ select "h3_section"
128
+ include "all"
129
+ insert_before 'h3_section where title:equals("Automation")'
130
+
131
+ from({
132
+ type: "inline",
133
+ markdown: "### Support Note\n\nThis note is inserted between two existing composed sections."
134
+ })
135
+ select "h3_section"
136
+ include "all"
137
+ insert_between 'Between h3_section where title:equals("Release Note") and h3_section where title:equals("Automation")'
138
+
139
+ # Replace Automation with Reporting, then insert Monitoring after Reporting.
140
+ from :current
141
+ select 'h3_section where title:equals("Reporting")'
142
+ include "heading_title"
143
+ include "paragraph[first:1]"
144
+ replace 'h3_section where title:equals("Automation")'
145
+
146
+ from :current
147
+ select 'h3_section where title:equals("Monitoring")'
148
+ include "heading_title"
149
+ include "paragraph[first:1]"
150
+ insert_after 'h3_section where title:equals("Reporting")'
151
+
152
+ # Copy a section, then let final dedupe remove the duplicate content.
153
+ from :buffer
154
+ select 'h3_section where title:equals("Release Note")'
155
+ include "all"
156
+ copy "end"
157
+
158
+ # Modify an existing buffer section in place with two nested transforms.
159
+ from :buffer
160
+ select 'h3_section where title:equals("Dashboard")'
161
+ include "all"
162
+ modify "in_place", transforms: [
163
+ {
164
+ "scope" => "heading_3, paragraph",
165
+ "transform" => "replace_text",
166
+ "mode" => "literal",
167
+ "options" => {
168
+ "from" => "Dashboard",
169
+ "to" => "Dashboard Snapshot"
170
+ }
171
+ },
172
+ {
173
+ "scope" => "paragraph[first:1]",
174
+ "transform" => "insert_after",
175
+ "mode" => "insert",
176
+ "options" => {
177
+ "content" => "This paragraph was inserted by the modify action before final output transforms run.",
178
+ "as" => "paragraph"
179
+ }
180
+ }
181
+ ]
182
+
183
+ # Move the preface into the document body.
184
+ from :buffer
185
+ select 'h3_section where title:equals("Complex Preface")'
186
+ include "all"
187
+ move 'after h2_section where title:equals("Feature Matrix")'
188
+
189
+ # Add and remove temporary content to demonstrate remove_buffer_target.
190
+ from({
191
+ type: "inline",
192
+ markdown: "### Cleanup Marker\n\nThis temporary marker exists only to demonstrate remove_buffer_target."
193
+ })
194
+ select "h3_section"
195
+ include "all"
196
+ append
197
+
198
+ from :buffer
199
+ select 'h3_section where title:equals("Cleanup Marker")'
200
+ remove_buffer_target
201
+
202
+ # Final output transforms shape the composed Markdown.
203
+ transform "output", "dedupe", "normalised_text"
204
+
205
+ transform "heading_2", "replace_text", "literal", {
206
+ "from" => "Feature Matrix",
207
+ "to" => "Complex Composer Walkthrough"
208
+ }
209
+
210
+ transform "link[first:1]", "links", "rewrite_url", {
211
+ "from" => "/features/dashboard",
212
+ "to" => "https://example.test/features/dashboard"
213
+ }
214
+
215
+ transform "heading", "heading_levels", "promote", {
216
+ "by" => 1
217
+ }
218
+
219
+ transform "paragraph[first:1]", "insert_after", "insert", {
220
+ "content" => "\n## Summary\n\nThis summary was inserted by a final transform after composition actions completed.",
221
+ "as" => "paragraph"
222
+ }
223
+ end
224
+
225
+ result = MarkdownComposer.compose(
226
+ sources: MarkdownComposer.source_list do
227
+ current File.read(File.join(root, "fixtures/current.md"))
228
+ explicit :guide, File.read(File.join(root, "fixtures/guide.md"))
229
+ explicit :faq, File.read(File.join(root, "fixtures/faq.md"))
230
+ inherited :site_intro, File.read(File.join(root, "fixtures/site_intro.md"))
231
+ end,
232
+ plan: plan
233
+ )
234
+
235
+ ExampleSupport.write_output(root, "complex_composer", result)
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ExampleSupport
4
+ module_function
5
+
6
+ # Keep example scripts small: fail loudly on Composer errors and write
7
+ # the generated Markdown beside the runnable examples.
8
+ def write_output(root, name, result)
9
+ abort result.errors.map(&:message).join("\n") unless result.success?
10
+
11
+ output_dir = File.join(root, "output")
12
+ Dir.mkdir(output_dir) unless Dir.exist?(output_dir)
13
+ path = File.join(output_dir, "#{name}.md")
14
+ File.write(path, result.markdown)
15
+ puts "Wrote #{path}"
16
+ puts result.markdown
17
+ end
18
+ end
@@ -0,0 +1,179 @@
1
+ # Product Knowledge Base
2
+
3
+ Welcome to the product knowledge base. This file is the main `current` source for runnable examples.
4
+
5
+ It intentionally contains several Markdown structures so you can experiment with selectors such as `h2_section`, `h3_section`, `paragraph[first:2]`, `table`, `code_block`, `mermaid`, and `math_block`.
6
+
7
+ ## Overview
8
+
9
+ This overview section is the normal starting point for Markdown Composer examples.
10
+
11
+ It includes [a product link](/features/dashboard), inline code `composer.preview`, and a second paragraph so include rules can choose content.
12
+
13
+ ### What Composer Should See
14
+
15
+ Composer should index nested sections under Overview and keep selected content in source order.
16
+
17
+ - The first bullet links to [getting started](/docs/getting-started).
18
+ - The second bullet mentions `source_list`.
19
+ - The third bullet is plain text for list-item selection.
20
+
21
+ #### Selector Notes
22
+
23
+ Use `h2_section[first:1]` to select the whole Overview section, including this H4.
24
+
25
+ Use `paragraph[first:1]` inside an include rule to keep only the first paragraph.
26
+
27
+ ### What Composer Should Ignore
28
+
29
+ This H3 gives you a second nested section to filter by title or position.
30
+
31
+ > Blockquotes are useful for testing paragraph and block-level extraction.
32
+
33
+ ## Feature Matrix
34
+
35
+ The table below is intended for table selection and table-row experiments.
36
+
37
+ | Feature | Status | Owner | Link |
38
+ | --- | --- | --- | --- |
39
+ | Dashboard | ready | Product | [Open](/features/dashboard) |
40
+ | Automation | beta | Platform | [Open](/features/automation) |
41
+ | Reporting | draft | Data | [Open](/features/reporting) |
42
+
43
+ ### Dashboard
44
+
45
+ Dashboard cards should keep this heading and paragraph when selected.
46
+
47
+ | Card | Visible |
48
+ | --- | --- |
49
+ | Summary | yes |
50
+ | Activity | yes |
51
+
52
+ ```ruby
53
+ class DashboardCard
54
+ def visible?
55
+ status == "ready"
56
+ end
57
+ end
58
+ ```
59
+
60
+ #### Dashboard Deep Dive
61
+
62
+ This H4 is nested under Dashboard and can be used to test deeper section boundaries.
63
+
64
+ ### Automation
65
+
66
+ Automation has two paragraphs so examples can select first or last content.
67
+
68
+ The second paragraph mentions API triggers, webhooks, retries, and scheduled jobs.
69
+
70
+ | Trigger | Retry |
71
+ | --- | --- |
72
+ | webhook | yes |
73
+ | schedule | yes |
74
+
75
+ ```bash
76
+ bundle exec ruby automation_rule.rb
77
+ ```
78
+
79
+ ```json
80
+ {
81
+ "feature": "automation",
82
+ "status": "beta",
83
+ "retries": 3
84
+ }
85
+ ```
86
+
87
+ ### Reporting
88
+
89
+ Reporting is marked draft so examples can filter it out by title or selected position.
90
+
91
+ ## Operations
92
+
93
+ Operations content gives the examples runbook-style Markdown.
94
+
95
+ ### Deployment
96
+
97
+ Deployment notes keep release steps short, repeatable, and easy to audit.
98
+
99
+ 1. Build the package.
100
+ 2. Run the test suite.
101
+ 3. Publish the generated gem.
102
+
103
+ ```bash
104
+ bundle exec rake test
105
+ gem build markdown_composer.gemspec
106
+ ```
107
+
108
+ #### Rollback
109
+
110
+ Rollback should happen only after the published package or integration has been verified.
111
+
112
+ ### Monitoring
113
+
114
+ Monitor compose success rate, validation errors, and unexpected empty selections.
115
+
116
+ ## Diagrams And Math
117
+
118
+ This section includes Mermaid and math examples.
119
+
120
+ ### Composition Flow
121
+
122
+ The composition flow diagram shows the order used by the examples.
123
+
124
+ ```mermaid
125
+ flowchart LR
126
+ Source --> Select
127
+ Select --> Include
128
+ Include --> Action
129
+ Action --> Buffer
130
+ Buffer --> Transform
131
+ ```
132
+
133
+ ### Score Formula
134
+
135
+ Inline math can appear in prose as `$score = selected / total$`.
136
+
137
+ Display math can appear as its own block:
138
+
139
+ ```math
140
+ precision = true_positive / (true_positive + false_positive)
141
+ ```
142
+
143
+ #### Formula Notes
144
+
145
+ Math blocks and inline math are useful for testing token preservation.
146
+
147
+ ## Draft Notes
148
+
149
+ This section is deliberately named Draft so examples can remove or filter it.
150
+
151
+ ### Cleanup Target
152
+
153
+ Use this nested section to test `where title:contains("Cleanup")` or `h3_section[last:1]`.
154
+
155
+ <!-- composer: removable draft comment -->
156
+
157
+ ## Appendix
158
+
159
+ The appendix gives the main fixture a fifth H2 section.
160
+
161
+ ### Source Types
162
+
163
+ Source type rows describe where content comes from during composition.
164
+
165
+ | Source | Meaning |
166
+ | --- | --- |
167
+ | current | Main runtime source |
168
+ | explicit | Keyed runtime source |
169
+ | inherited | Host-resolved runtime source |
170
+ | inline | Plan-row source content |
171
+
172
+ ### Copy-Paste Checklist
173
+
174
+ Use this checklist when adapting the examples to a local script.
175
+
176
+ - Read files with `File.read`.
177
+ - Build sources with `MarkdownComposer.source_list`.
178
+ - Build plans with `MarkdownComposer.plan` or `MarkdownComposer.parse_yaml`.
179
+ - Run `MarkdownComposer.compose`.