logs: migrate to molecular CoT JSON protocol, fix regressions
- Replace BeliefFormatter with CotJsonFormatter (single-line JSON with ts, level, trace_id, src, marker, intent, payload, error, span_id) - Migrate belief_scope to use cot_log() for structured JSON output - Update monkey-patched reason/reflect/explore to pass extra= dict - Strip 200+ inline [REASON]/[REFLECT]/[EXPLORE] markers from 50+ files - Remove belief_scope from hot-path utilities (_parse_datetime, _json_load_if_needed) to eliminate startup log noise - Register TraceContextMiddleware in app.py (was implemented but unused) - Seed trace_id in startup_event/shutdown_event for background tasks - Fix broken relative imports in translate routes (3 dots → 4 dots) - Migrate 43 translate_routes log calls to logger.reason/explore - Fix SyntaxError (positional arg after extra=) in _repo_operations_routes - Fix IndentationError in rbac_permission_catalog except-block - Add smoke test tests/test_smoke_app.py (catches import errors before run)
This commit is contained in:
@@ -133,7 +133,7 @@ class GitServiceBase:
|
||||
if source_abs == target_abs:
|
||||
return source_abs
|
||||
if os.path.exists(target_abs):
|
||||
logger.warning(f"[_migrate_repo_directory][REASON] Target already exists, keeping source path: {target_abs}")
|
||||
logger.reason(f"Target already exists, keeping source path: {target_abs}", extra={"src": "_migrate_repo_directory"})
|
||||
return source_abs
|
||||
Path(target_abs).parent.mkdir(parents=True, exist_ok=True)
|
||||
try:
|
||||
@@ -210,11 +210,11 @@ class GitServiceBase:
|
||||
else:
|
||||
auth_url = remote_url
|
||||
if os.path.exists(repo_path):
|
||||
logger.info(f"[init_repo][REASON] Opening existing repo at {repo_path}")
|
||||
logger.reason(f"Opening existing repo at {repo_path}", extra={"src": "init_repo"})
|
||||
try:
|
||||
repo = Repo(repo_path)
|
||||
except (InvalidGitRepositoryError, NoSuchPathError):
|
||||
logger.warning(f"[init_repo][REASON] Existing path is not a Git repository, recreating: {repo_path}")
|
||||
logger.reason(f"Existing path is not a Git repository, recreating: {repo_path}", extra={"src": "init_repo"})
|
||||
stale_path = Path(repo_path)
|
||||
if stale_path.exists():
|
||||
shutil.rmtree(stale_path, ignore_errors=True)
|
||||
@@ -226,7 +226,7 @@ class GitServiceBase:
|
||||
repo = Repo.clone_from(auth_url, repo_path)
|
||||
self._ensure_gitflow_branches(repo, dashboard_id)
|
||||
return repo
|
||||
logger.info(f"[init_repo][REASON] Cloning {remote_url} to {repo_path}")
|
||||
logger.reason(f"Cloning {remote_url} to {repo_path}", extra={"src": "init_repo"})
|
||||
repo = Repo.clone_from(auth_url, repo_path)
|
||||
self._ensure_gitflow_branches(repo, dashboard_id)
|
||||
return repo
|
||||
@@ -307,7 +307,7 @@ class GitServiceBase:
|
||||
with repo.config_writer(config_level="repository") as config_writer:
|
||||
config_writer.set_value("user", "name", normalized_username)
|
||||
config_writer.set_value("user", "email", normalized_email)
|
||||
logger.info("[configure_identity][REASON] Applied repository-local git identity for dashboard %s", dashboard_id)
|
||||
logger.reason(f"Applied repository-local git identity for dashboard {dashboard_id}", extra={"src": "configure_identity"})
|
||||
except Exception as e:
|
||||
logger.error(f"[configure_identity][Coherence:Failed] Failed to configure git identity: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"Failed to configure git identity: {str(e)}")
|
||||
|
||||
@@ -31,25 +31,28 @@ class GitServiceBranchMixin:
|
||||
if "main" in local_heads:
|
||||
base_commit = local_heads["main"].commit
|
||||
if base_commit is None:
|
||||
logger.warning(
|
||||
f"[_ensure_gitflow_branches][REASON] Skipping branch bootstrap for dashboard {dashboard_id}: repository has no commits"
|
||||
logger.reason(
|
||||
f"Skipping branch bootstrap for dashboard {dashboard_id}: repository has no commits",
|
||||
extra={"src": "_ensure_gitflow_branches"},
|
||||
)
|
||||
return
|
||||
if "main" not in local_heads:
|
||||
local_heads["main"] = repo.create_head("main", base_commit)
|
||||
logger.info(f"[_ensure_gitflow_branches][REASON] Created local branch main for dashboard {dashboard_id}")
|
||||
logger.reason(f"Created local branch main for dashboard {dashboard_id}", extra={"src": "_ensure_gitflow_branches"})
|
||||
for branch_name in ("dev", "preprod"):
|
||||
if branch_name in local_heads:
|
||||
continue
|
||||
local_heads[branch_name] = repo.create_head(branch_name, local_heads["main"].commit)
|
||||
logger.info(
|
||||
f"[_ensure_gitflow_branches][REASON] Created local branch {branch_name} for dashboard {dashboard_id}"
|
||||
logger.reason(
|
||||
f"Created local branch {branch_name} for dashboard {dashboard_id}",
|
||||
extra={"src": "_ensure_gitflow_branches"},
|
||||
)
|
||||
try:
|
||||
origin = repo.remote(name="origin")
|
||||
except ValueError:
|
||||
logger.info(
|
||||
f"[_ensure_gitflow_branches][REASON] Remote origin is not configured for dashboard {dashboard_id}; skipping remote branch creation"
|
||||
logger.reason(
|
||||
f"Remote origin is not configured for dashboard {dashboard_id}; skipping remote branch creation",
|
||||
extra={"src": "_ensure_gitflow_branches"},
|
||||
)
|
||||
return
|
||||
remote_branch_names = set()
|
||||
@@ -60,14 +63,15 @@ class GitServiceBranchMixin:
|
||||
if remote_head:
|
||||
remote_branch_names.add(str(remote_head))
|
||||
except Exception as e:
|
||||
logger.warning(f"[_ensure_gitflow_branches][REASON] Failed to fetch origin refs: {e}")
|
||||
logger.reason(f"Failed to fetch origin refs: {e}", extra={"src": "_ensure_gitflow_branches"})
|
||||
for branch_name in required_branches:
|
||||
if branch_name in remote_branch_names:
|
||||
continue
|
||||
try:
|
||||
origin.push(refspec=f"{branch_name}:{branch_name}")
|
||||
logger.info(
|
||||
f"[_ensure_gitflow_branches][REASON] Pushed branch {branch_name} to origin for dashboard {dashboard_id}"
|
||||
logger.reason(
|
||||
f"Pushed branch {branch_name} to origin for dashboard {dashboard_id}",
|
||||
extra={"src": "_ensure_gitflow_branches"},
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"[_ensure_gitflow_branches][Coherence:Failed] Failed to push branch {branch_name} to origin: {e}")
|
||||
@@ -77,9 +81,9 @@ class GitServiceBranchMixin:
|
||||
)
|
||||
try:
|
||||
repo.git.checkout("dev")
|
||||
logger.info(f"[_ensure_gitflow_branches][REASON] Checked out default branch dev for dashboard {dashboard_id}")
|
||||
logger.reason(f"Checked out default branch dev for dashboard {dashboard_id}", extra={"src": "_ensure_gitflow_branches"})
|
||||
except Exception as e:
|
||||
logger.warning(f"[_ensure_gitflow_branches][REASON] Could not checkout dev branch for dashboard {dashboard_id}: {e}")
|
||||
logger.reason(f"Could not checkout dev branch for dashboard {dashboard_id}: {e}", extra={"src": "_ensure_gitflow_branches"})
|
||||
# [/DEF:_ensure_gitflow_branches:Function]
|
||||
|
||||
# [DEF:list_branches:Function]
|
||||
@@ -90,7 +94,7 @@ class GitServiceBranchMixin:
|
||||
def list_branches(self, dashboard_id: int) -> List[dict]:
|
||||
with belief_scope("GitService.list_branches"):
|
||||
repo = self.get_repo(dashboard_id)
|
||||
logger.info(f"[list_branches][REASON] Listing branches for {dashboard_id}. Refs: {repo.refs}")
|
||||
logger.reason(f"Listing branches for {dashboard_id}. Refs: {repo.refs}", extra={"src": "list_branches"})
|
||||
branches = []
|
||||
for ref in repo.refs:
|
||||
try:
|
||||
@@ -104,7 +108,7 @@ class GitServiceBranchMixin:
|
||||
"last_updated": datetime.fromtimestamp(ref.commit.committed_date) if hasattr(ref, 'commit') else datetime.utcnow()
|
||||
})
|
||||
except Exception as e:
|
||||
logger.warning(f"[list_branches][REASON] Skipping ref {ref}: {e}")
|
||||
logger.reason(f"Skipping ref {ref}: {e}", extra={"src": "list_branches"})
|
||||
try:
|
||||
active_name = repo.active_branch.name
|
||||
if not any(b['name'] == active_name for b in branches):
|
||||
@@ -113,7 +117,7 @@ class GitServiceBranchMixin:
|
||||
"is_remote": False, "last_updated": datetime.utcnow()
|
||||
})
|
||||
except Exception as e:
|
||||
logger.warning(f"[list_branches][REASON] Could not determine active branch: {e}")
|
||||
logger.reason(f"Could not determine active branch: {e}", extra={"src": "list_branches"})
|
||||
if not branches:
|
||||
branches.append({
|
||||
"name": "dev", "commit_hash": "0000000",
|
||||
@@ -131,9 +135,9 @@ class GitServiceBranchMixin:
|
||||
def create_branch(self, dashboard_id: int, name: str, from_branch: str = "main"):
|
||||
with belief_scope("GitService.create_branch"):
|
||||
repo = self.get_repo(dashboard_id)
|
||||
logger.info(f"[create_branch][REASON] Creating branch {name} from {from_branch}")
|
||||
logger.reason(f"Creating branch {name} from {from_branch}", extra={"src": "create_branch"})
|
||||
if not repo.heads and not repo.remotes:
|
||||
logger.warning("[create_branch][REASON] Repository is empty. Creating initial commit to enable branching.")
|
||||
logger.reason("Repository is empty. Creating initial commit to enable branching.", extra={"src": "create_branch"})
|
||||
readme_path = os.path.join(repo.working_dir, "README.md")
|
||||
if not os.path.exists(readme_path):
|
||||
with open(readme_path, "w") as f:
|
||||
@@ -143,7 +147,7 @@ class GitServiceBranchMixin:
|
||||
try:
|
||||
repo.commit(from_branch)
|
||||
except Exception:
|
||||
logger.warning(f"[create_branch][REASON] Source branch {from_branch} not found, using HEAD")
|
||||
logger.reason(f"Source branch {from_branch} not found, using HEAD", extra={"src": "create_branch"})
|
||||
from_branch = repo.head
|
||||
try:
|
||||
new_branch = repo.create_head(name, from_branch)
|
||||
@@ -160,7 +164,7 @@ class GitServiceBranchMixin:
|
||||
def checkout_branch(self, dashboard_id: int, name: str):
|
||||
with belief_scope("GitService.checkout_branch"):
|
||||
repo = self.get_repo(dashboard_id)
|
||||
logger.info(f"[checkout_branch][REASON] Checking out branch {name}")
|
||||
logger.reason(f"Checking out branch {name}", extra={"src": "checkout_branch"})
|
||||
repo.git.checkout(name)
|
||||
# [/DEF:checkout_branch:Function]
|
||||
|
||||
@@ -174,13 +178,13 @@ class GitServiceBranchMixin:
|
||||
with belief_scope("GitService.commit_changes"):
|
||||
repo = self.get_repo(dashboard_id)
|
||||
if not repo.is_dirty(untracked_files=True) and not files:
|
||||
logger.info(f"[commit_changes][REASON] No changes to commit for dashboard {dashboard_id}")
|
||||
logger.reason(f"No changes to commit for dashboard {dashboard_id}", extra={"src": "commit_changes"})
|
||||
return
|
||||
if files:
|
||||
logger.info(f"[commit_changes][REASON] Staging files: {files}")
|
||||
logger.reason(f"Staging files: {files}", extra={"src": "commit_changes"})
|
||||
repo.index.add(files)
|
||||
else:
|
||||
logger.info("[commit_changes][REASON] Staging all changes")
|
||||
logger.reason("Staging all changes", extra={"src": "commit_changes"})
|
||||
repo.git.add(A=True)
|
||||
repo.index.commit(message)
|
||||
logger.info(f"[commit_changes][Coherence:OK] Committed changes with message: {message}")
|
||||
|
||||
@@ -23,7 +23,7 @@ class GitServiceGiteaMixin:
|
||||
async def test_connection(self, provider: GitProvider, url: str, pat: str) -> bool:
|
||||
with belief_scope("GitService.test_connection"):
|
||||
if ".local" in url or "localhost" in url:
|
||||
logger.info("[test_connection][REASON] Local/Offline mode detected for URL")
|
||||
logger.reason("Local/Offline mode detected for URL", extra={"src": "test_connection"})
|
||||
return True
|
||||
if not url.startswith(('http://', 'https://')):
|
||||
logger.error(f"[test_connection][Coherence:Failed] Invalid URL protocol: {url}")
|
||||
@@ -220,9 +220,9 @@ class GitServiceGiteaMixin:
|
||||
exc.status_code == 404 and fallback_url and fallback_url != normalized_primary
|
||||
)
|
||||
if should_retry_with_fallback:
|
||||
logger.warning(
|
||||
"[create_gitea_pull_request][REASON] Primary Gitea URL not found, retrying with remote host: %s",
|
||||
fallback_url,
|
||||
logger.explore(
|
||||
f"Primary Gitea URL not found, retrying with remote host: {fallback_url}",
|
||||
extra={"src": "create_gitea_pull_request"},
|
||||
)
|
||||
active_server_url = fallback_url
|
||||
try:
|
||||
|
||||
@@ -153,7 +153,7 @@ class GitServiceStatusMixin:
|
||||
"files_changed": list(commit.stats.files.keys())
|
||||
})
|
||||
except Exception as e:
|
||||
logger.warning(f"[get_commit_history][REASON] Could not retrieve commit history for dashboard {dashboard_id}: {e}")
|
||||
logger.explore(f"Could not retrieve commit history for dashboard {dashboard_id}: {e}", extra={"src": "get_commit_history"})
|
||||
return []
|
||||
return commits
|
||||
# [/DEF:get_commit_history:Function]
|
||||
|
||||
@@ -60,9 +60,9 @@ class GitServiceSyncMixin:
|
||||
finally:
|
||||
session.close()
|
||||
except Exception as diag_error:
|
||||
logger.warning(
|
||||
"[push_changes][REASON] Failed to load repository binding diagnostics for dashboard %s: %s",
|
||||
dashboard_id, diag_error,
|
||||
logger.reason(
|
||||
"Failed to load repository binding diagnostics",
|
||||
extra={"src": "push_changes", "dashboard_id": dashboard_id, "error": str(diag_error)},
|
||||
)
|
||||
realigned_origin_url = self._align_origin_host_with_config(
|
||||
dashboard_id=dashboard_id,
|
||||
@@ -75,13 +75,13 @@ class GitServiceSyncMixin:
|
||||
origin_urls = list(origin.urls)
|
||||
except Exception:
|
||||
origin_urls = []
|
||||
logger.info(
|
||||
"[push_changes][REASON] Push diagnostics dashboard=%s config_id=%s config_url=%s binding_remote_url=%s origin_urls=%s origin_realigned=%s",
|
||||
dashboard_id, binding_config_id, binding_config_url, binding_remote_url, origin_urls, bool(realigned_origin_url),
|
||||
logger.reason(
|
||||
f"Push diagnostics dashboard={dashboard_id} config_id={binding_config_id} config_url={binding_config_url} binding_remote_url={binding_remote_url} origin_urls={origin_urls} origin_realigned={bool(realigned_origin_url)}",
|
||||
extra={"src": "push_changes"},
|
||||
)
|
||||
try:
|
||||
current_branch = repo.active_branch
|
||||
logger.info(f"[push_changes][REASON] Pushing branch {current_branch.name} to origin")
|
||||
logger.reason(f"Pushing branch {current_branch.name} to origin", extra={"src": "push_changes"})
|
||||
tracking_branch = None
|
||||
try:
|
||||
tracking_branch = current_branch.tracking_branch()
|
||||
@@ -120,10 +120,9 @@ class GitServiceSyncMixin:
|
||||
merge_head_path = os.path.join(repo.git_dir, "MERGE_HEAD")
|
||||
if os.path.exists(merge_head_path):
|
||||
payload = self._build_unfinished_merge_payload(repo)
|
||||
logger.warning(
|
||||
"[pull_changes][REASON] Unfinished merge detected for dashboard %s (repo_path=%s git_dir=%s branch=%s merge_head=%s merge_msg=%s)",
|
||||
dashboard_id, payload["repository_path"], payload["git_dir"],
|
||||
payload["current_branch"], payload["merge_head"], payload["merge_message_preview"],
|
||||
logger.reason(
|
||||
f"Unfinished merge detected for dashboard {dashboard_id} (repo_path={payload['repository_path']} git_dir={payload['git_dir']} branch={payload['current_branch']} merge_head={payload['merge_head']} merge_msg={payload['merge_message_preview']})",
|
||||
extra={"src": "pull_changes"},
|
||||
)
|
||||
raise HTTPException(status_code=409, detail=payload)
|
||||
try:
|
||||
@@ -133,23 +132,23 @@ class GitServiceSyncMixin:
|
||||
origin_urls = list(origin.urls)
|
||||
except Exception:
|
||||
origin_urls = []
|
||||
logger.info(
|
||||
"[pull_changes][REASON] Pull diagnostics dashboard=%s repo_path=%s branch=%s origin_urls=%s",
|
||||
dashboard_id, repo.working_tree_dir, current_branch, origin_urls,
|
||||
logger.reason(
|
||||
f"Pull diagnostics dashboard={dashboard_id} repo_path={repo.working_tree_dir} branch={current_branch} origin_urls={origin_urls}",
|
||||
extra={"src": "pull_changes"},
|
||||
)
|
||||
origin.fetch(prune=True)
|
||||
remote_ref = f"origin/{current_branch}"
|
||||
has_remote_branch = any(ref.name == remote_ref for ref in repo.refs)
|
||||
logger.info(
|
||||
"[pull_changes][REASON] Pull remote branch check dashboard=%s branch=%s remote_ref=%s exists=%s",
|
||||
dashboard_id, current_branch, remote_ref, has_remote_branch,
|
||||
logger.reason(
|
||||
f"Pull remote branch check dashboard={dashboard_id} branch={current_branch} remote_ref={remote_ref} exists={has_remote_branch}",
|
||||
extra={"src": "pull_changes"},
|
||||
)
|
||||
if not has_remote_branch:
|
||||
raise HTTPException(
|
||||
status_code=409,
|
||||
detail=f"Remote branch '{current_branch}' does not exist yet. Push this branch first.",
|
||||
)
|
||||
logger.info(f"[pull_changes][REASON] Pulling changes from origin/{current_branch}")
|
||||
logger.reason(f"Pulling changes from origin/{current_branch}", extra={"src": "pull_changes"})
|
||||
repo.git.pull("--no-rebase", "origin", current_branch)
|
||||
except ValueError:
|
||||
logger.error(f"[pull_changes][Coherence:Failed] Remote 'origin' not found for dashboard {dashboard_id}")
|
||||
|
||||
@@ -115,9 +115,9 @@ class GitServiceUrlMixin:
|
||||
aligned_url = self._replace_host_in_url(source_origin_url, config_url)
|
||||
if not aligned_url:
|
||||
return None
|
||||
logger.warning(
|
||||
"[_align_origin_host_with_config][REASON] Host mismatch for dashboard %s: config_host=%s origin_host=%s, applying origin.set_url",
|
||||
dashboard_id, config_host, origin_host,
|
||||
logger.reason(
|
||||
f"Host mismatch for dashboard {dashboard_id}: config_host={config_host} origin_host={origin_host}, applying origin.set_url",
|
||||
extra={"src": "_align_origin_host_with_config"},
|
||||
)
|
||||
try:
|
||||
origin.set_url(aligned_url)
|
||||
@@ -141,9 +141,9 @@ class GitServiceUrlMixin:
|
||||
finally:
|
||||
session.close()
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
"[_align_origin_host_with_config][REASON] Failed to persist aligned remote_url for dashboard %s: %s",
|
||||
dashboard_id, e,
|
||||
logger.explore(
|
||||
f"Failed to persist aligned remote_url for dashboard {dashboard_id}: {e}",
|
||||
extra={"src": "_align_origin_host_with_config"},
|
||||
)
|
||||
return aligned_url
|
||||
# [/DEF:_align_origin_host_with_config:Function]
|
||||
|
||||
Reference in New Issue
Block a user