Skip to content

Commit 5cc44a7

Browse files
DOC-6026 further tree improvements
1 parent a417fe7 commit 5cc44a7

File tree

4 files changed

+101
-38
lines changed

4 files changed

+101
-38
lines changed

build/render_hook_docs/DECISION_TREE_FORMAT.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ questions:
4949
- **`scope`** (required): Category or domain this tree applies to (e.g., `documents`, `collections`, `sequences`). Helps AI agents understand the tree's purpose and applicability.
5050
- **`rootQuestion`** (required): The ID of the starting question
5151
- **`questions`** (required): Object containing all questions, keyed by ID
52+
- **`indentWidth`** (optional): Horizontal spacing in pixels between parent and child nodes. Default: 40. Use smaller values (e.g., 20-30) for deeply nested trees to reduce overall width. This is a rendering preference and does not affect the semantic metadata.
5253

5354
### Question Object
5455

@@ -138,6 +139,7 @@ scope: documents
138139
8. **Add sentiment for suitability trees**: If your tree determines whether something is suitable (not just choosing between options), use `sentiment: "positive"` and `sentiment: "negative"` to provide visual feedback
139140
9. **Be consistent with sentiment**: In a suitability tree, ensure all positive outcomes have `sentiment: "positive"` and all negative outcomes have `sentiment: "negative"` for clarity
140141
10. **Control answer order**: The order of `yes` and `no` in the YAML controls the visual layout. For early rejection patterns, put `no` first so negative outcomes appear on the left side of the diagram
142+
11. **Adjust indent width for deeply nested trees**: If your tree has many levels and becomes too wide, use `indentWidth="25"` (or lower) in the code block fence to reduce horizontal spacing between parent and child nodes
141143
142144
## Example: Redis Data Type Selection
143145

build/render_hook_docs/DECISION_TREE_IMPLEMENTATION_NOTES.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,60 @@ answerLabel = item.answer || 'Yes'; // Use stored value, not position
197197

198198
**Key Insight**: YAML object key order is preserved in JavaScript (since ES2015), and we now respect both the order AND the actual answer values, making the layout fully author-controlled.
199199

200+
## 13. Configurable Indent Width for Deeply Nested Trees
201+
202+
**Problem**: Deeply nested decision trees (with many levels of questions) can become too wide to fit on the page, requiring horizontal scrolling.
203+
204+
**Solution**: Added optional `indentWidth` parameter to the YAML root object that controls the horizontal spacing between parent and child nodes:
205+
206+
```yaml
207+
id: when-to-use-rdi
208+
scope: rdi
209+
indentWidth: 25 # Reduce from default 40 to make tree narrower
210+
rootQuestion: cacheTarget
211+
questions:
212+
# ...
213+
```
214+
215+
**Implementation**:
216+
In `renderDecisionTree()`, the indent width is read from `treeData.indentWidth` with a sensible default:
217+
```javascript
218+
const indentWidth = treeData.indentWidth ? parseInt(treeData.indentWidth) : 40;
219+
```
220+
221+
**Design Rationale**: While `indentWidth` is a rendering preference, it's included in the YAML because:
222+
1. Hugo's Goldmark attribute parsing doesn't reliably expose custom attributes from the code block info string to the render hook
223+
2. Including it in the YAML keeps all tree configuration in one place
224+
3. AI agents can still access the semantic metadata (id, scope, questions) separately from rendering preferences
225+
226+
**Benefit**: Authors can now control tree width by adjusting `indentWidth`:
227+
- Default (40): Comfortable spacing for shallow trees
228+
- Reduced (20-30): Compact layout for deeply nested trees
229+
- The SVG width is calculated as: `leftMargin + (maxDepth + 1) * indentWidth + maxBoxWidth + 40`
230+
231+
**Recommendation**: For trees with 8+ levels of nesting, try `indentWidth: 25` or lower to keep the diagram readable without horizontal scrolling.
232+
233+
## 14. Improved Label Visibility with Reduced Indent Width
234+
235+
**Problem**: When using reduced `indentWidth` values, the Yes/No labels on the connecting lines were being covered by the node boxes they referred to.
236+
237+
**Solution**:
238+
1. Increased the vertical offset of labels from `y + 10` to `y + 16` pixels
239+
2. Added a white background rectangle behind each label to ensure visibility even when overlapping with boxes
240+
241+
**Implementation**:
242+
```javascript
243+
const labelY = y + 16; // Increased offset
244+
245+
// Add white background rectangle behind label
246+
const labelBg = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
247+
labelBg.setAttribute('x', labelX - 12);
248+
labelBg.setAttribute('y', labelY - 9);
249+
labelBg.setAttribute('width', '24');
250+
labelBg.setAttribute('height', '12');
251+
labelBg.setAttribute('fill', 'white');
252+
svg.appendChild(labelBg);
253+
```
254+
255+
**Benefit**: Labels remain readable regardless of indent width or tree density.
256+

content/integrate/redis-data-integration/when-to-use.md

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ Use the decision tree below to determine whether RDI is a good fit for your arch
7171
```decision-tree {id="when-to-use-rdi"}
7272
id: when-to-use-rdi
7373
scope: rdi
74+
indentWidth: 25
7475
rootQuestion: cacheTarget
7576
questions:
7677
cacheTarget:
@@ -82,7 +83,7 @@ questions:
8283
no:
8384
value: "No"
8485
outcome:
85-
label: "RDI is not necessary - you don't need Redis as a cache"
86+
label: "RDI only works with Redis as the target database"
8687
id: noRedisCache
8788
sentiment: "negative"
8889
yes:
@@ -97,39 +98,24 @@ questions:
9798
no:
9899
value: "No"
99100
outcome:
100-
label: "RDI won't work - you need a single source database"
101+
label: "RDI won't work with multiple source databases"
101102
id: multipleSourcesOrActiveActive
102103
sentiment: "negative"
103104
yes:
104105
value: "Yes"
105106
nextQuestion: systemOfRecord
106107
systemOfRecord:
107108
text: |
108-
Is the source database your system of record?
109+
Does your app always *write* to the source database and not to Redis?
109110
whyAsk: |
110111
RDI requires the source database to be the authoritative source of truth. If your app writes to Redis first, RDI won't work.
111112
answers:
112113
no:
113114
value: "No"
114115
outcome:
115-
label: "RDI won't work - the source database must be the system of record"
116+
label: "RDI doesn't support syncing data from Redis back to the source database"
116117
id: notSystemOfRecord
117118
sentiment: "negative"
118-
yes:
119-
value: "Yes"
120-
nextQuestion: appWritesToDb
121-
appWritesToDb:
122-
text: |
123-
Does your app always write its data to the source database?
124-
whyAsk: |
125-
RDI requires the app to write to the source database first. If your app writes to Redis first, RDI cannot maintain consistency.
126-
answers:
127-
no:
128-
value: "No"
129-
outcome:
130-
label: "RDI won't work - your app must write to the source database"
131-
id: appWritesToRedis
132-
sentiment: "negative"
133119
yes:
134120
value: "Yes"
135121
nextQuestion: consistency
@@ -142,7 +128,7 @@ questions:
142128
no:
143129
value: "No"
144130
outcome:
145-
label: "RDI is not suitable - you need immediate cache consistency"
131+
label: "RDI does not provide immediate cache consistency"
146132
id: needsImmediate
147133
sentiment: "negative"
148134
yes:
@@ -195,33 +181,33 @@ questions:
195181
nextQuestion: dataSize
196182
dataSize:
197183
text: |
198-
Is your total data size not larger than 100GB?
184+
Is your total data size smaller than 100GB?
199185
whyAsk: |
200186
RDI has practical limits on the total data size it can manage. Very large datasets may exceed these limits.
201187
answers:
202188
no:
203189
value: "No"
204190
outcome:
205-
label: "RDI may not be suitable - your data set is too large"
191+
label: "RDI may not be suitable - your data set is probably too large"
206192
id: dataTooLarge
207193
sentiment: "negative"
208194
yes:
209195
value: "Yes"
210196
nextQuestion: joins
211197
joins:
212198
text: |
213-
Do you not need to perform join operations on data from several tables into a nested Redis JSON object?
199+
Do you need to perform join operations on data from several tables into a nested Redis JSON object?
214200
whyAsk: |
215201
RDI has limitations with complex join operations. If you need to combine data from multiple tables into nested structures, you may need custom transformations.
216202
answers:
217-
no:
218-
value: "No"
203+
yes:
204+
value: "Yes"
219205
outcome:
220206
label: "RDI may not be suitable - complex joins are not well supported"
221207
id: complexJoins
222208
sentiment: "negative"
223-
yes:
224-
value: "Yes"
209+
no:
210+
value: "No"
225211
nextQuestion: transformations
226212
transformations:
227213
text: |
@@ -232,22 +218,23 @@ questions:
232218
no:
233219
value: "No"
234220
outcome:
235-
label: "RDI may not be suitable - required transformations are not supported"
221+
label: "RDI may not be able to perform the required data transformations"
236222
id: unsupportedTransformations
237223
sentiment: "negative"
238224
yes:
239225
value: "Yes"
240226
nextQuestion: adminReview
241227
adminReview:
242228
text: |
243-
Has your database administrator reviewed and confirmed that RDI's requirements for the source database are acceptable?
229+
Has your database administrator reviewed RDI's requirements for the source database
230+
and confirmed they are acceptable?
244231
whyAsk: |
245232
RDI has specific requirements for the source database (binary logging, permissions, etc.). Your DBA must confirm these are acceptable before proceeding.
246233
answers:
247234
no:
248235
value: "No"
249236
outcome:
250-
label: "RDI is not suitable - database administrator has rejected RDI's requirements"
237+
label: "RDI requirements for the source database can't be met"
251238
id: adminRejected
252239
sentiment: "negative"
253240
yes:

static/js/decision-tree.js

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
const items = [];
7070
const visited = new Set();
7171

72-
function traverse(nodeId, depth) {
72+
function traverse(nodeId, depth, parentAnswer = null) {
7373
if (visited.has(nodeId)) return;
7474
visited.add(nodeId);
7575

@@ -81,7 +81,8 @@
8181
depth: depth,
8282
type: 'question',
8383
text: question.text || '',
84-
whyAsk: question.whyAsk || ''
84+
whyAsk: question.whyAsk || '',
85+
answer: parentAnswer // Store the answer that led to this question
8586
});
8687

8788
if (question.answers) {
@@ -92,15 +93,19 @@
9293
answerKeys.forEach(answerKey => {
9394
const answer = question.answers[answerKey];
9495
if (answer) {
96+
// Store the answer value for use in tree line labels
97+
const answerValue = answer.value || answerKey.charAt(0).toUpperCase() + answerKey.slice(1);
98+
9599
if (answer.nextQuestion) {
96-
traverse(answer.nextQuestion, depth + 1);
100+
// Traverse to next question, passing the answer value
101+
traverse(answer.nextQuestion, depth + 1, answerValue);
97102
} else if (answer.outcome) {
98103
items.push({
99104
id: answer.outcome.id,
100105
depth: depth + 1,
101106
type: 'outcome',
102107
text: answer.outcome.label || '',
103-
answer: answer.value || answerKey.charAt(0).toUpperCase() + answerKey.slice(1),
108+
answer: answerValue,
104109
sentiment: answer.outcome.sentiment || null
105110
});
106111
}
@@ -147,7 +152,8 @@
147152
const charWidth = 8;
148153
const leftMargin = 20;
149154
const topMargin = 10;
150-
const indentWidth = 40; // Increased from 24 for wider indent
155+
// Allow indentWidth to be customized via YAML, default to 40
156+
const indentWidth = treeData.indentWidth ? parseInt(treeData.indentWidth) : 40;
151157
const boxPadding = 12; // Increased from 8 for more padding
152158
const maxBoxWidth = 420; // Increased to accommodate longer questions
153159
const maxCharsPerLine = Math.floor(maxBoxWidth / charWidth);
@@ -305,9 +311,20 @@
305311
hline.setAttribute('stroke-width', '1');
306312
svg.appendChild(hline);
307313

308-
// Add answer label on the horizontal line, positioned below it to avoid boxes
309-
const labelX = connectorX + (boxX + hlineExtension - connectorX) / 2;
310-
const labelY = y + 10;
314+
// Add answer label on the horizontal line, positioned to the left to avoid box overlap
315+
// Position label closer to parent box, shifted left by the indent amount
316+
const labelX = connectorX + (indentWidth * 0.3); // Position at 30% of the way across
317+
const labelY = y + 16; // Increased offset to avoid box overlap
318+
319+
// Add white background rectangle behind label for visibility
320+
const labelBg = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
321+
labelBg.setAttribute('x', labelX - 12);
322+
labelBg.setAttribute('y', labelY - 9);
323+
labelBg.setAttribute('width', '24');
324+
labelBg.setAttribute('height', '12');
325+
labelBg.setAttribute('fill', 'white');
326+
labelBg.setAttribute('stroke', 'none');
327+
svg.appendChild(labelBg);
311328

312329
const label = document.createElementNS('http://www.w3.org/2000/svg', 'text');
313330
label.setAttribute('x', labelX);

0 commit comments

Comments
 (0)