chore: add MERGE-DEBUG traces for project_root lifecycle
Temporary diagnostic logging to track why project_root becomes None during merge pipeline operations. Tagged with MERGE-DEBUG for easy grep-and-remove once the root cause is confirmed fixed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1580,7 +1580,17 @@ async fn tool_merge_agent_work(args: &Value, ctx: &AppContext) -> Result<String,
|
|||||||
.ok_or("Missing required argument: story_id")?;
|
.ok_or("Missing required argument: story_id")?;
|
||||||
let agent_name = args.get("agent_name").and_then(|v| v.as_str());
|
let agent_name = args.get("agent_name").and_then(|v| v.as_str());
|
||||||
|
|
||||||
|
// TRACE:MERGE-DEBUG — remove once root cause is found
|
||||||
|
crate::slog!(
|
||||||
|
"[MERGE-DEBUG] tool_merge_agent_work called for story_id={:?}, agent_name={:?}",
|
||||||
|
story_id,
|
||||||
|
agent_name
|
||||||
|
);
|
||||||
let project_root = ctx.agents.get_project_root(&ctx.state)?;
|
let project_root = ctx.agents.get_project_root(&ctx.state)?;
|
||||||
|
crate::slog!(
|
||||||
|
"[MERGE-DEBUG] tool_merge_agent_work: project_root resolved to {:?}",
|
||||||
|
project_root
|
||||||
|
);
|
||||||
let report = ctx.agents.merge_agent_work(&project_root, story_id).await?;
|
let report = ctx.agents.merge_agent_work(&project_root, story_id).await?;
|
||||||
|
|
||||||
let status_msg = if report.success && report.gates_passed && report.conflicts_resolved {
|
let status_msg = if report.success && report.gates_passed && report.conflicts_resolved {
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ impl ProjectApi {
|
|||||||
/// Close the current project and clear the stored selection.
|
/// Close the current project and clear the stored selection.
|
||||||
#[oai(path = "/project", method = "delete")]
|
#[oai(path = "/project", method = "delete")]
|
||||||
async fn close_project(&self) -> OpenApiResult<Json<bool>> {
|
async fn close_project(&self) -> OpenApiResult<Json<bool>> {
|
||||||
|
// TRACE:MERGE-DEBUG — remove once root cause is found
|
||||||
|
crate::slog_error!(
|
||||||
|
"[MERGE-DEBUG] DELETE /project called! \
|
||||||
|
Backtrace: this is the only code path that clears project_root."
|
||||||
|
);
|
||||||
fs::close_project(&self.ctx.state, self.ctx.store.as_ref()).map_err(bad_request)?;
|
fs::close_project(&self.ctx.state, self.ctx.store.as_ref()).map_err(bad_request)?;
|
||||||
Ok(Json(true))
|
Ok(Json(true))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -532,6 +532,8 @@ pub async fn open_project(
|
|||||||
let _ = worktree_write_mcp_json(&p, port);
|
let _ = worktree_write_mcp_json(&p, port);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
// TRACE:MERGE-DEBUG — remove once root cause is found
|
||||||
|
crate::slog!("[MERGE-DEBUG] open_project: setting project_root to {:?}", p);
|
||||||
let mut root = state.project_root.lock().map_err(|e| e.to_string())?;
|
let mut root = state.project_root.lock().map_err(|e| e.to_string())?;
|
||||||
*root = Some(p);
|
*root = Some(p);
|
||||||
}
|
}
|
||||||
@@ -551,6 +553,8 @@ pub async fn open_project(
|
|||||||
|
|
||||||
pub fn close_project(state: &SessionState, store: &dyn StoreOps) -> Result<(), String> {
|
pub fn close_project(state: &SessionState, store: &dyn StoreOps) -> Result<(), String> {
|
||||||
{
|
{
|
||||||
|
// TRACE:MERGE-DEBUG — remove once root cause is found
|
||||||
|
crate::slog!("[MERGE-DEBUG] close_project: setting project_root to None");
|
||||||
let mut root = state.project_root.lock().map_err(|e| e.to_string())?;
|
let mut root = state.project_root.lock().map_err(|e| e.to_string())?;
|
||||||
*root = None;
|
*root = None;
|
||||||
}
|
}
|
||||||
@@ -579,6 +583,12 @@ pub fn get_current_project(
|
|||||||
{
|
{
|
||||||
let p = PathBuf::from(path_str);
|
let p = PathBuf::from(path_str);
|
||||||
if p.exists() && p.is_dir() {
|
if p.exists() && p.is_dir() {
|
||||||
|
// TRACE:MERGE-DEBUG — remove once root cause is found
|
||||||
|
crate::slog!(
|
||||||
|
"[MERGE-DEBUG] get_current_project: project_root was None, \
|
||||||
|
restoring from store to {:?}",
|
||||||
|
p
|
||||||
|
);
|
||||||
let mut root = state.project_root.lock().map_err(|e| e.to_string())?;
|
let mut root = state.project_root.lock().map_err(|e| e.to_string())?;
|
||||||
*root = Some(p);
|
*root = Some(p);
|
||||||
return Ok(Some(path_str.to_string()));
|
return Ok(Some(path_str.to_string()));
|
||||||
|
|||||||
@@ -94,6 +94,8 @@ async fn main() -> Result<(), std::io::Error> {
|
|||||||
.unwrap_or_else(|e| panic!("Invalid project.toml: {e}"));
|
.unwrap_or_else(|e| panic!("Invalid project.toml: {e}"));
|
||||||
} else {
|
} else {
|
||||||
// No .story_kit/ found — fall back to cwd so existing behaviour is preserved.
|
// No .story_kit/ found — fall back to cwd so existing behaviour is preserved.
|
||||||
|
// TRACE:MERGE-DEBUG — remove once root cause is found
|
||||||
|
slog!("[MERGE-DEBUG] main: no .story_kit/ found, falling back to cwd {:?}", cwd);
|
||||||
*app_state.project_root.lock().unwrap() = Some(cwd.clone());
|
*app_state.project_root.lock().unwrap() = Some(cwd.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,9 +22,15 @@ impl Default for SessionState {
|
|||||||
impl SessionState {
|
impl SessionState {
|
||||||
pub fn get_project_root(&self) -> Result<PathBuf, String> {
|
pub fn get_project_root(&self) -> Result<PathBuf, String> {
|
||||||
let root_guard = self.project_root.lock().map_err(|e| e.to_string())?;
|
let root_guard = self.project_root.lock().map_err(|e| e.to_string())?;
|
||||||
let root = root_guard
|
let root = root_guard.as_ref().ok_or_else(|| {
|
||||||
.as_ref()
|
// TRACE:MERGE-DEBUG — remove once root cause is found
|
||||||
.ok_or_else(|| "No project is currently open.".to_string())?;
|
crate::slog_error!(
|
||||||
|
"[MERGE-DEBUG] get_project_root() called but project_root is None! \
|
||||||
|
Backtrace hint: check caller in MCP tool handler."
|
||||||
|
);
|
||||||
|
"No project is currently open.".to_string()
|
||||||
|
})?;
|
||||||
Ok(root.clone())
|
Ok(root.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user