MCPcopy Create free account
hub / github.com/ScriptedAlchemy/tracedecay / record_hook_span_observation

Method record_hook_span_observation

src/mcp/server.rs:2776–2863  ·  view source on GitHub ↗

Records a live session↔git span from one hook route notification. Route metadata carries `(session_id, thread_id, cwd, worktree, branch)`; when the route names a session and resolves to a registered project, this folds one [`SpanObservation`] into that project's `sessions.db` span table (see [`crate::sessions::git_correlation`]). Mid-session branch/worktree switches are handled by the span table

(&self, event: &hook_events::HookEvent)

Source from the content-addressed store, hash-verified

2774 /// merge regardless, so a dropped observation only widens a span slightly
2775 /// less).
2776 async fn record_hook_span_observation(&self, event: &hook_events::HookEvent) {
2777 use crate::sessions::git_correlation::{
2778 self as gc, SpanObservation, SpanSource, DEFAULT_SPAN_MERGE_GAP_SECS,
2779 DEFAULT_SPAN_OBSERVATION_DEBOUNCE_SECS,
2780 };
2781
2782 let Some(route) = event.route.as_ref() else {
2783 return;
2784 };
2785 let Some(session_id) = route
2786 .session_id
2787 .as_deref()
2788 .map(str::trim)
2789 .filter(|value| !value.is_empty())
2790 else {
2791 return;
2792 };
2793 // Resolve the project for this route the same way route caching does;
2794 // spans belong to that project's store, not this server's checkout.
2795 let route_cwd = route.cwd.as_deref().or(event.cwd.as_deref());
2796 let Some(cwd) = route_cwd else {
2797 return;
2798 };
2799 let Some(project_root) = self.registered_project_for_route_cwd(cwd).await else {
2800 return;
2801 };
2802 let project_root = PathBuf::from(project_root);
2803
2804 // Worktree preference: the routed worktree, else the cwd's git
2805 // worktree root, else the resolved project root. Never fabricated.
2806 let worktree_raw = route
2807 .worktree
2808 .as_deref()
2809 .map(Path::to_path_buf)
2810 .or_else(|| crate::worktree::git_worktree_root(cwd))
2811 .unwrap_or_else(|| project_root.clone());
2812 let worktree = gc::normalize_worktree(&worktree_raw.to_string_lossy());
2813
2814 let branch = route
2815 .branch
2816 .as_deref()
2817 .map(str::trim)
2818 .filter(|value| !value.is_empty())
2819 .map(str::to_string);
2820 let thread_id = route
2821 .thread_id
2822 .as_deref()
2823 .map(str::trim)
2824 .filter(|value| !value.is_empty())
2825 .map(str::to_string);
2826 let ts = crate::tracedecay::current_timestamp();
2827
2828 // Hook routes are provider-agnostic: leave provider empty.
2829 let key = gc::span_debounce_key("", session_id, branch.as_deref(), &worktree);
2830 let should_record = self
2831 .span_observation_debounce
2832 .lock()
2833 .map_or(true, |mut debounce| {

Callers 1

Calls 10

git_worktree_rootFunction · 0.85
normalize_worktreeFunction · 0.85
current_timestampFunction · 0.85
span_debounce_keyFunction · 0.85
should_recordMethod · 0.80
is_emptyMethod · 0.45

Tested by

no test coverage detected