debug logs demotion

Orual 4c9f8b6f 55d185bc

+228 -21
+19 -21
crates/weaver-editor-browser/src/dom_sync.rs
··· 99 let anchor_offset = selection.anchor_offset() as usize; 100 let focus_offset = selection.focus_offset() as usize; 101 102 - tracing::debug!( 103 anchor_node_name = %anchor_node.node_name(), 104 anchor_offset, 105 focus_node_name = %focus_node.node_name(), ··· 166 .text_content() 167 .map(|s| s.chars().take(20).collect::<String>()) 168 .unwrap_or_default(); 169 - tracing::debug!( 170 node_name = %node_name, 171 node_id_attr = ?node_id_attr, 172 text_preview = %text_content_preview.escape_debug(), ··· 180 // offset_in_text_node is the offset within that descendant, NOT the 181 // child index in the editor. 182 if let Some(ref walked_node) = walked_from { 183 - tracing::debug!( 184 walked_from_node_name = %walked_node.node_name(), 185 "dom_position_to_text_offset: walked up to editor from descendant" 186 ); ··· 208 209 // Selection is directly on the editor container (e.g., Cmd+A). 210 let child_count = editor_element.child_element_count() as usize; 211 - tracing::debug!( 212 offset_in_text_node, 213 child_count, 214 "dom_position_to_text_offset: selection directly on editor container" 215 ); 216 if offset_in_text_node == 0 { 217 - tracing::debug!( 218 "dom_position_to_text_offset: returning 0 (editor container offset 0)" 219 ); 220 return Some(0); 221 } else if offset_in_text_node >= child_count { 222 let end = paragraphs.last().map(|p| p.char_range.end); 223 - tracing::debug!(end = ?end, "dom_position_to_text_offset: returning end of last paragraph"); 224 return end; 225 } 226 break None; ··· 233 if let Some(id) = id { 234 // Match both old-style "n0" and paragraph-prefixed "p-2-n0" node IDs. 235 let is_node_id = id.starts_with('n') || id.contains("-n"); 236 - tracing::debug!( 237 id = %id, 238 is_node_id, 239 - starts_with_n = id.starts_with('n'), 240 - contains_dash_n = id.contains("-n"), 241 "dom_position_to_text_offset: checking ID pattern" 242 ); 243 if is_node_id { ··· 253 let node_id = match node_id { 254 Some(id) => id, 255 None => { 256 - tracing::debug!("dom_position_to_text_offset: no node_id found in walk-up"); 257 return None; 258 } 259 }; 260 261 - tracing::debug!(node_id = %node_id, "dom_position_to_text_offset: found node_id"); 262 263 let container = dom_document.get_element_by_id(&node_id).or_else(|| { 264 let selector = format!("[data-node-id='{}']", node_id); ··· 288 } 289 utf16_offset_in_container = text_counted; 290 291 - tracing::debug!( 292 child_index, 293 utf16_offset = utf16_offset_in_container, 294 "dom_position_to_text_offset: node is container, using child index" ··· 387 388 // Check if position is valid (not on invisible content). 389 if is_valid_cursor_position(&para.offset_map, char_offset) { 390 - tracing::debug!( 391 char_offset, 392 "dom_position_to_text_offset: returning valid position from mapping" 393 ); ··· 398 if let Some(snapped) = 399 find_nearest_valid_position(&para.offset_map, char_offset, direction_hint) 400 { 401 - tracing::debug!( 402 original = char_offset, 403 snapped = snapped.char_offset(), 404 "dom_position_to_text_offset: snapped from invisible to valid" ··· 407 } 408 409 // Fallback to original if no snap target. 410 - tracing::debug!( 411 char_offset, 412 "dom_position_to_text_offset: returning original (no snap target)" 413 ); ··· 422 if utf16_offset_in_container > max_end { 423 // Cursor is past the end of tracked content - snap to end of last mapping. 424 let char_offset = mapping.char_range.end; 425 - tracing::debug!( 426 node_id = %node_id, 427 utf16_offset = utf16_offset_in_container, 428 max_tracked_end = max_end, ··· 440 .and_then(|rest| rest.split('-').next()) 441 .and_then(|idx_str| idx_str.parse::<usize>().ok()); 442 443 - tracing::debug!( 444 node_id = %node_id, 445 utf16_offset = utf16_offset_in_container, 446 para_idx_from_node = ?para_idx_from_node, ··· 454 if let Some(snapped) = 455 find_nearest_valid_position(&para.offset_map, para.char_range.start, direction_hint) 456 { 457 - tracing::debug!( 458 para_id = %para.id, 459 snapped_offset = snapped.char_offset(), 460 "dom_position_to_text_offset: fallback to matching paragraph" ··· 469 if let Some(snapped) = 470 find_nearest_valid_position(&para.offset_map, para.char_range.start, direction_hint) 471 { 472 - tracing::debug!( 473 para_id = %para.id, 474 snapped_offset = snapped.char_offset(), 475 "dom_position_to_text_offset: fallback to first available paragraph" ··· 643 let expected_len = new_para.byte_range.end - new_para.byte_range.start; 644 let dom_len = dom_text.len(); 645 let matches = dom_len == expected_len; 646 - tracing::debug!( 647 para_id = %para_id, 648 dom_len, 649 expected_len, ··· 689 .map(|p| p.now()) 690 { 691 let elapsed_ms = end_time - start_time; 692 - tracing::debug!( 693 para_id = %para_id, 694 is_cursor_para, 695 elapsed_ms,
··· 99 let anchor_offset = selection.anchor_offset() as usize; 100 let focus_offset = selection.focus_offset() as usize; 101 102 + tracing::trace!( 103 anchor_node_name = %anchor_node.node_name(), 104 anchor_offset, 105 focus_node_name = %focus_node.node_name(), ··· 166 .text_content() 167 .map(|s| s.chars().take(20).collect::<String>()) 168 .unwrap_or_default(); 169 + tracing::trace!( 170 node_name = %node_name, 171 node_id_attr = ?node_id_attr, 172 text_preview = %text_content_preview.escape_debug(), ··· 180 // offset_in_text_node is the offset within that descendant, NOT the 181 // child index in the editor. 182 if let Some(ref walked_node) = walked_from { 183 + tracing::trace!( 184 walked_from_node_name = %walked_node.node_name(), 185 "dom_position_to_text_offset: walked up to editor from descendant" 186 ); ··· 208 209 // Selection is directly on the editor container (e.g., Cmd+A). 210 let child_count = editor_element.child_element_count() as usize; 211 + tracing::trace!( 212 offset_in_text_node, 213 child_count, 214 "dom_position_to_text_offset: selection directly on editor container" 215 ); 216 if offset_in_text_node == 0 { 217 + tracing::trace!( 218 "dom_position_to_text_offset: returning 0 (editor container offset 0)" 219 ); 220 return Some(0); 221 } else if offset_in_text_node >= child_count { 222 let end = paragraphs.last().map(|p| p.char_range.end); 223 + tracing::trace!(end = ?end, "dom_position_to_text_offset: returning end of last paragraph"); 224 return end; 225 } 226 break None; ··· 233 if let Some(id) = id { 234 // Match both old-style "n0" and paragraph-prefixed "p-2-n0" node IDs. 235 let is_node_id = id.starts_with('n') || id.contains("-n"); 236 + tracing::trace!( 237 id = %id, 238 is_node_id, 239 "dom_position_to_text_offset: checking ID pattern" 240 ); 241 if is_node_id { ··· 251 let node_id = match node_id { 252 Some(id) => id, 253 None => { 254 + tracing::trace!("dom_position_to_text_offset: no node_id found in walk-up"); 255 return None; 256 } 257 }; 258 259 + tracing::trace!(node_id = %node_id, "dom_position_to_text_offset: found node_id"); 260 261 let container = dom_document.get_element_by_id(&node_id).or_else(|| { 262 let selector = format!("[data-node-id='{}']", node_id); ··· 286 } 287 utf16_offset_in_container = text_counted; 288 289 + tracing::trace!( 290 child_index, 291 utf16_offset = utf16_offset_in_container, 292 "dom_position_to_text_offset: node is container, using child index" ··· 385 386 // Check if position is valid (not on invisible content). 387 if is_valid_cursor_position(&para.offset_map, char_offset) { 388 + tracing::trace!( 389 char_offset, 390 "dom_position_to_text_offset: returning valid position from mapping" 391 ); ··· 396 if let Some(snapped) = 397 find_nearest_valid_position(&para.offset_map, char_offset, direction_hint) 398 { 399 + tracing::trace!( 400 original = char_offset, 401 snapped = snapped.char_offset(), 402 "dom_position_to_text_offset: snapped from invisible to valid" ··· 405 } 406 407 // Fallback to original if no snap target. 408 + tracing::trace!( 409 char_offset, 410 "dom_position_to_text_offset: returning original (no snap target)" 411 ); ··· 420 if utf16_offset_in_container > max_end { 421 // Cursor is past the end of tracked content - snap to end of last mapping. 422 let char_offset = mapping.char_range.end; 423 + tracing::trace!( 424 node_id = %node_id, 425 utf16_offset = utf16_offset_in_container, 426 max_tracked_end = max_end, ··· 438 .and_then(|rest| rest.split('-').next()) 439 .and_then(|idx_str| idx_str.parse::<usize>().ok()); 440 441 + tracing::trace!( 442 node_id = %node_id, 443 utf16_offset = utf16_offset_in_container, 444 para_idx_from_node = ?para_idx_from_node, ··· 452 if let Some(snapped) = 453 find_nearest_valid_position(&para.offset_map, para.char_range.start, direction_hint) 454 { 455 + tracing::trace!( 456 para_id = %para.id, 457 snapped_offset = snapped.char_offset(), 458 "dom_position_to_text_offset: fallback to matching paragraph" ··· 467 if let Some(snapped) = 468 find_nearest_valid_position(&para.offset_map, para.char_range.start, direction_hint) 469 { 470 + tracing::trace!( 471 para_id = %para.id, 472 snapped_offset = snapped.char_offset(), 473 "dom_position_to_text_offset: fallback to first available paragraph" ··· 641 let expected_len = new_para.byte_range.end - new_para.byte_range.start; 642 let dom_len = dom_text.len(); 643 let matches = dom_len == expected_len; 644 + tracing::trace!( 645 para_id = %para_id, 646 dom_len, 647 expected_len, ··· 687 .map(|p| p.now()) 688 { 689 let elapsed_ms = end_time - start_time; 690 + tracing::trace!( 691 para_id = %para_id, 692 is_cursor_para, 693 elapsed_ms,
+209
docs/graph-data.json
··· 2254 "created_at": "2026-01-07T19:55:00.600569229-05:00", 2255 "updated_at": "2026-01-07T19:55:00.600569229-05:00", 2256 "metadata_json": "{\"confidence\":95}" 2257 } 2258 ], 2259 "edges": [ ··· 4434 "weight": 1.0, 4435 "rationale": "CSS fix for word wrapping", 4436 "created_at": "2026-01-07T19:55:00.626395757-05:00" 4437 } 4438 ] 4439 }
··· 2254 "created_at": "2026-01-07T19:55:00.600569229-05:00", 2255 "updated_at": "2026-01-07T19:55:00.600569229-05:00", 2256 "metadata_json": "{\"confidence\":95}" 2257 + }, 2258 + { 2259 + "id": 207, 2260 + "change_id": "6e278837-7bb3-40dd-aad7-467036dff90b", 2261 + "node_type": "goal", 2262 + "title": "Fix editor cursor/navigation bugs reported by users", 2263 + "description": null, 2264 + "status": "pending", 2265 + "created_at": "2026-01-07T21:15:29.543538706-05:00", 2266 + "updated_at": "2026-01-07T21:15:29.543538706-05:00", 2267 + "metadata_json": "{\"confidence\":90,\"prompt\":\"User reported multiple cursor bugs: jumping to position 0, blank line navigation, arrow key issues\"}" 2268 + }, 2269 + { 2270 + "id": 208, 2271 + "change_id": "7b7accb1-8c16-4015-9182-103d2969cbf0", 2272 + "node_type": "outcome", 2273 + "title": "Blank line navigation fix - acceptable", 2274 + "description": null, 2275 + "status": "pending", 2276 + "created_at": "2026-01-07T21:15:35.376075796-05:00", 2277 + "updated_at": "2026-01-07T21:15:35.376075796-05:00", 2278 + "metadata_json": "{\"confidence\":75,\"prompt\":\"Changed gap emission: first newline=ZWSP only, additional newlines=literal newline+ZWSP. Browser can now navigate to blank lines, some minor cursor jank remains but usable.\"}" 2279 + }, 2280 + { 2281 + "id": 209, 2282 + "change_id": "b2c90081-c941-4f18-88a3-28a7e11a79e6", 2283 + "node_type": "observation", 2284 + "title": "Login hang after OAuth callback - fixed", 2285 + "description": null, 2286 + "status": "pending", 2287 + "created_at": "2026-01-07T21:15:45.287601993-05:00", 2288 + "updated_at": "2026-01-07T21:15:45.287601993-05:00", 2289 + "metadata_json": "{\"confidence\":95,\"prompt\":\"Added early exit in restore_session when already authenticated\"}" 2290 + }, 2291 + { 2292 + "id": 210, 2293 + "change_id": "b013b975-f1a7-459c-b369-7a9edc1d6f4b", 2294 + "node_type": "observation", 2295 + "title": "Ctrl+A select all - fixed by letting browser handle natively", 2296 + "description": null, 2297 + "status": "pending", 2298 + "created_at": "2026-01-07T21:15:49.045740296-05:00", 2299 + "updated_at": "2026-01-07T21:15:49.045740296-05:00", 2300 + "metadata_json": "{\"confidence\":95}" 2301 + }, 2302 + { 2303 + "id": 211, 2304 + "change_id": "d9d668e9-960f-423d-ae32-8c4c0ecae1e6", 2305 + "node_type": "observation", 2306 + "title": "Long line overflow - fixed with overflow-wrap CSS", 2307 + "description": null, 2308 + "status": "pending", 2309 + "created_at": "2026-01-07T21:15:53.560541581-05:00", 2310 + "updated_at": "2026-01-07T21:15:53.560541581-05:00", 2311 + "metadata_json": "{\"confidence\":90}" 2312 + }, 2313 + { 2314 + "id": 212, 2315 + "change_id": "ab71b5ea-a010-42bb-a113-ae6a2ec2fe4e", 2316 + "node_type": "observation", 2317 + "title": "Enter 4+ times cursor jump - potentially fixed by gap emission changes", 2318 + "description": null, 2319 + "status": "pending", 2320 + "created_at": "2026-01-07T21:15:58.586155730-05:00", 2321 + "updated_at": "2026-01-07T21:15:58.586155730-05:00", 2322 + "metadata_json": "{\"confidence\":40}" 2323 + }, 2324 + { 2325 + "id": 213, 2326 + "change_id": "a041c1fb-3253-409a-aae7-a558187d99e4", 2327 + "node_type": "observation", 2328 + "title": "Double return behavior - potentially fixed by gap emission changes", 2329 + "description": null, 2330 + "status": "pending", 2331 + "created_at": "2026-01-07T21:16:03.703238206-05:00", 2332 + "updated_at": "2026-01-07T21:16:03.703238206-05:00", 2333 + "metadata_json": "{\"confidence\":35}" 2334 + }, 2335 + { 2336 + "id": 214, 2337 + "change_id": "252761df-21fe-408b-902d-fbd00252efbc", 2338 + "node_type": "observation", 2339 + "title": "Selecting/deleting links - still open, needs verification", 2340 + "description": null, 2341 + "status": "pending", 2342 + "created_at": "2026-01-07T21:16:07.366725128-05:00", 2343 + "updated_at": "2026-01-07T21:16:07.366725128-05:00", 2344 + "metadata_json": "{\"confidence\":20}" 2345 } 2346 ], 2347 "edges": [ ··· 4522 "weight": 1.0, 4523 "rationale": "CSS fix for word wrapping", 4524 "created_at": "2026-01-07T19:55:00.626395757-05:00" 4525 + }, 4526 + { 4527 + "id": 200, 4528 + "from_node_id": 207, 4529 + "to_node_id": 208, 4530 + "from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b", 4531 + "to_change_id": "7b7accb1-8c16-4015-9182-103d2969cbf0", 4532 + "edge_type": "leads_to", 4533 + "weight": 1.0, 4534 + "rationale": "Implemented gap emission fix for blank line navigation", 4535 + "created_at": "2026-01-07T21:15:39.826116361-05:00" 4536 + }, 4537 + { 4538 + "id": 201, 4539 + "from_node_id": 207, 4540 + "to_node_id": 209, 4541 + "from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b", 4542 + "to_change_id": "b2c90081-c941-4f18-88a3-28a7e11a79e6", 4543 + "edge_type": "leads_to", 4544 + "weight": 1.0, 4545 + "rationale": "Fixed during bug investigation", 4546 + "created_at": "2026-01-07T21:16:13.866616170-05:00" 4547 + }, 4548 + { 4549 + "id": 202, 4550 + "from_node_id": 207, 4551 + "to_node_id": 210, 4552 + "from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b", 4553 + "to_change_id": "b013b975-f1a7-459c-b369-7a9edc1d6f4b", 4554 + "edge_type": "leads_to", 4555 + "weight": 1.0, 4556 + "rationale": "Fixed during bug investigation", 4557 + "created_at": "2026-01-07T21:16:14.010017763-05:00" 4558 + }, 4559 + { 4560 + "id": 203, 4561 + "from_node_id": 207, 4562 + "to_node_id": 211, 4563 + "from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b", 4564 + "to_change_id": "d9d668e9-960f-423d-ae32-8c4c0ecae1e6", 4565 + "edge_type": "leads_to", 4566 + "weight": 1.0, 4567 + "rationale": "Fixed during bug investigation", 4568 + "created_at": "2026-01-07T21:16:14.108510907-05:00" 4569 + }, 4570 + { 4571 + "id": 204, 4572 + "from_node_id": 207, 4573 + "to_node_id": 212, 4574 + "from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b", 4575 + "to_change_id": "ab71b5ea-a010-42bb-a113-ae6a2ec2fe4e", 4576 + "edge_type": "leads_to", 4577 + "weight": 1.0, 4578 + "rationale": "May be fixed by gap emission changes", 4579 + "created_at": "2026-01-07T21:16:14.231726582-05:00" 4580 + }, 4581 + { 4582 + "id": 205, 4583 + "from_node_id": 207, 4584 + "to_node_id": 213, 4585 + "from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b", 4586 + "to_change_id": "a041c1fb-3253-409a-aae7-a558187d99e4", 4587 + "edge_type": "leads_to", 4588 + "weight": 1.0, 4589 + "rationale": "May be fixed by gap emission changes", 4590 + "created_at": "2026-01-07T21:16:14.330604847-05:00" 4591 + }, 4592 + { 4593 + "id": 206, 4594 + "from_node_id": 207, 4595 + "to_node_id": 214, 4596 + "from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b", 4597 + "to_change_id": "252761df-21fe-408b-902d-fbd00252efbc", 4598 + "edge_type": "leads_to", 4599 + "weight": 1.0, 4600 + "rationale": "Still needs investigation", 4601 + "created_at": "2026-01-07T21:16:14.411257422-05:00" 4602 + }, 4603 + { 4604 + "id": 207, 4605 + "from_node_id": 207, 4606 + "to_node_id": 203, 4607 + "from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b", 4608 + "to_change_id": "7f5f61d9-67a2-4743-bf6e-64df19ee991c", 4609 + "edge_type": "leads_to", 4610 + "weight": 1.0, 4611 + "rationale": "Previously fixed wikilink issue", 4612 + "created_at": "2026-01-07T21:16:32.811831732-05:00" 4613 + }, 4614 + { 4615 + "id": 208, 4616 + "from_node_id": 207, 4617 + "to_node_id": 204, 4618 + "from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b", 4619 + "to_change_id": "5bddd314-fd5a-487b-b9fb-25a7150a71ed", 4620 + "edge_type": "leads_to", 4621 + "weight": 1.0, 4622 + "rationale": "Previously fixed blockquote issue", 4623 + "created_at": "2026-01-07T21:16:32.828122843-05:00" 4624 + }, 4625 + { 4626 + "id": 209, 4627 + "from_node_id": 207, 4628 + "to_node_id": 205, 4629 + "from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b", 4630 + "to_change_id": "2e1776c7-94aa-47f4-b1b3-63898529335e", 4631 + "edge_type": "leads_to", 4632 + "weight": 1.0, 4633 + "rationale": "Fixed login hang", 4634 + "created_at": "2026-01-07T21:16:32.844654254-05:00" 4635 + }, 4636 + { 4637 + "id": 210, 4638 + "from_node_id": 207, 4639 + "to_node_id": 206, 4640 + "from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b", 4641 + "to_change_id": "2ff2950e-e749-4d6e-b524-27217a323be0", 4642 + "edge_type": "leads_to", 4643 + "weight": 1.0, 4644 + "rationale": "Fixed overflow", 4645 + "created_at": "2026-01-07T21:16:32.861314215-05:00" 4646 } 4647 ] 4648 }