From 0c8d9252c35f9b4c3a2138fe39cb64adaa43c2b9 Mon Sep 17 00:00:00 2001 From: unknown <356261005@qq.com> Date: Sat, 20 Jun 2026 00:49:29 +0800 Subject: [PATCH 1/2] Add diagnostic redaction regression tests --- build.py | 222 ++++++++++++++++++--- tests/test_diagnostic_regression.py | 299 ++++++++++++++++++++++++++++ 2 files changed, 489 insertions(+), 32 deletions(-) create mode 100644 tests/test_diagnostic_regression.py diff --git a/build.py b/build.py index 07b97c41..e7429636 100644 --- a/build.py +++ b/build.py @@ -10,9 +10,10 @@ import subprocess import sys import time +import tempfile from dataclasses import dataclass -from pathlib import Path -from typing import Optional +from pathlib import Path, PurePosixPath, PureWindowsPath +from typing import Any, Optional ROOT = Path(__file__).resolve().parent DIAGNOSTIC_DIR = ROOT / "diagnostic" @@ -20,6 +21,113 @@ ENCRYPTLY_BLOCKER_MESSAGE = "You need to fix your environment so encryptly runs before building." +class DiagnosticValidationError(RuntimeError): + pass + + +def repo_relative_path(path: Path | str) -> str: + """Return a deterministic repo-relative path using forward slashes.""" + path_obj = Path(path) + if not path_obj.is_absolute(): + return str(path).replace("\\", "/") + try: + return path_obj.resolve().relative_to(ROOT.resolve()).as_posix() + except ValueError: + return f"external/{path_obj.name}" + + +def _redaction_tokens() -> list[tuple[str, str]]: + tokens = [ + (str(ROOT), ""), + (str(Path.home()), ""), + (tempfile.gettempdir(), ""), + (platform.node(), ""), + (getpass.getuser(), ""), + ] + for key in ("USERNAME", "USER", "LOGNAME", "COMPUTERNAME"): + value = os.environ.get(key) + if value: + tokens.append((value, f"<{key.lower()}>")) + + expanded: list[tuple[str, str]] = [] + for token, replacement in tokens: + if not token: + continue + expanded.append((token, replacement)) + expanded.append((token.replace("\\", "/"), replacement)) + expanded.append((token.replace("/", "\\"), replacement)) + + expanded.sort(key=lambda item: len(item[0]), reverse=True) + return expanded + + +def redact_diagnostic_text(value: str) -> str: + redacted = value + for token, replacement in _redaction_tokens(): + redacted = redacted.replace(token, replacement) + return redacted + + +def sanitize_diagnostic_value(value: Any) -> Any: + if isinstance(value, dict): + return {key: sanitize_diagnostic_value(item) for key, item in value.items()} + if isinstance(value, list): + return [sanitize_diagnostic_value(item) for item in value] + if isinstance(value, tuple): + return [sanitize_diagnostic_value(item) for item in value] + if isinstance(value, Path): + return repo_relative_path(value) + if isinstance(value, str): + return redact_diagnostic_text(value) + return value + + +def validate_diagnostic_pair( + metadata_path: Path, + expected_logd_paths: Optional[list[Path]] = None, +) -> None: + if not metadata_path.exists(): + raise DiagnosticValidationError( + f"diagnostic metadata JSON missing: {repo_relative_path(metadata_path)}" + ) + + try: + metadata = json.loads(metadata_path.read_text(encoding="utf-8")) + except json.JSONDecodeError as exc: + raise DiagnosticValidationError( + f"diagnostic metadata JSON invalid: {repo_relative_path(metadata_path)}: {exc}" + ) from exc + + logd_value = metadata.get("diagnostic_logd") + if not logd_value: + if metadata.get("diagnostic_logd_error"): + return + raise DiagnosticValidationError( + f"diagnostic_logd missing in {repo_relative_path(metadata_path)}" + ) + + logd_refs = logd_value if isinstance(logd_value, list) else [logd_value] + normalized_refs: list[str] = [] + for ref in logd_refs: + if not isinstance(ref, str) or not ref.strip(): + raise DiagnosticValidationError("diagnostic_logd must contain non-empty path strings") + normalized_ref = ref.replace("\\", "/") + ref_path = Path(normalized_ref) + if ref_path.is_absolute() or PureWindowsPath(ref).is_absolute() or PurePosixPath(ref).is_absolute(): + raise DiagnosticValidationError(f"diagnostic_logd must be repo-relative: {ref}") + artifact_path = ROOT.joinpath(*normalized_ref.split("/")) + if not artifact_path.exists(): + raise DiagnosticValidationError(f"diagnostic .logd missing: {normalized_ref}") + normalized_refs.append(normalized_ref) + + if expected_logd_paths is not None: + expected = [repo_relative_path(path) for path in expected_logd_paths] + if normalized_refs != expected: + raise DiagnosticValidationError( + f"diagnostic_logd mismatch: metadata has {normalized_refs}, expected {expected}" + ) + + def current_commit_id() -> str: """Return the first 4 bytes (8 hex chars) of HEAD for stable per-commit diagnostics.""" try: @@ -222,7 +330,7 @@ def encryptly_platform_help() -> str: return f"detected {detected}; available: {available}" -def check_encryptly_runs(timeout: int = 60) -> tuple[bool, str]: +def check_encryptly_runs(timeout: int = 180) -> tuple[bool, str]: """Verify encryptly can create a diagnostic bundle before doing any build work.""" encryptly_bin = get_encryptly_bin() if encryptly_bin is None: @@ -230,9 +338,14 @@ def check_encryptly_runs(timeout: int = 60) -> tuple[bool, str]: workspace = Path.home() / ".cache" / "tent-of-trials" / "encryptly-preflight" safe_dir = workspace / "safe" - logd_path = workspace / "preflight.logd" + # Keep the output outside the included tree. Some encryptly builds stream the + # destination while walking --include, which can otherwise pack the growing + # .logd into itself and make the preflight hang or balloon. + logd_path = workspace.parent / "preflight.logd" try: shutil.rmtree(workspace, ignore_errors=True) + if logd_path.exists(): + logd_path.unlink() safe_dir.mkdir(parents=True, exist_ok=True) (safe_dir / "preflight.txt").write_text("encryptly preflight\n", encoding="utf-8") result = subprocess.run( @@ -262,6 +375,8 @@ def check_encryptly_runs(timeout: int = 60) -> tuple[bool, str]: return False, str(e) finally: shutil.rmtree(workspace, ignore_errors=True) + if logd_path.exists(): + logd_path.unlink() class Colors: GREEN = "\033[92m" @@ -277,6 +392,43 @@ def color(text: str, code: str) -> str: return text return f"{code}{text}{Colors.RESET}" + +def output_supports(text: str) -> bool: + encoding = (getattr(sys.stdout, "encoding", None) or "utf-8").lower().replace("_", "-") + if encoding not in {"utf-8", "utf8", "cp65001"}: + return False + try: + text.encode(encoding) + return True + except UnicodeEncodeError: + return False + + +def safe_text(text: str, fallback: str) -> str: + return text if output_supports(text) else fallback + + +def mark(symbol: str, fallback: str) -> str: + return safe_text(symbol, fallback) + + +def rule(width: int) -> str: + return safe_text("─" * width, "-" * width) + + +def configure_output_streams() -> None: + for stream in (sys.stdout, sys.stderr): + reconfigure = getattr(stream, "reconfigure", None) + if reconfigure is None: + continue + try: + reconfigure(errors="replace") + except Exception: + pass + + +configure_output_streams() + def check_prerequisites() -> list[str]: required = { "cargo": "Rust", @@ -306,7 +458,7 @@ def build_module( verbose: bool = False, ) -> tuple[bool, float, str]: - print(f"\n {color('▸', Colors.CYAN)} Building {color(module.name, Colors.BOLD)} ({module.language})...") + print(f"\n {color(mark('▸', '>'), Colors.CYAN)} Building {color(module.name, Colors.BOLD)} ({module.language})...") env = os.environ.copy() if module.env: @@ -329,6 +481,8 @@ def build_module( ) if install_result.returncode != 0: return False, time.time() - start, f"npm install failed:\n{install_result.stderr}" + except FileNotFoundError as e: + return False, time.time() - start, f"npm install command not found: {e}" except subprocess.TimeoutExpired: return False, time.time() - start, "npm install TIMEOUT (120s)" @@ -348,7 +502,7 @@ def build_module( except subprocess.TimeoutExpired: return False, time.time() - start, "CMake configure TIMEOUT (120s)" except FileNotFoundError as e: - return False, 0, f"Command not found: {e}" + return False, time.time() - start, f"CMake configure command not found: {e}" if cfg_result.returncode != 0: output_lines = [] if cfg_result.stdout: @@ -397,7 +551,7 @@ def build_module( return success, elapsed, output def clean_module(module: Module, verbose: bool = False) -> bool: - print(f" {color('▸', Colors.YELLOW)} Cleaning {module.name}...") + print(f" {color(mark('▸', '>'), Colors.YELLOW)} Cleaning {module.name}...") try: subprocess.run( module.clean_cmd, @@ -409,7 +563,7 @@ def clean_module(module: Module, verbose: bool = False) -> bool: ) return True except Exception as e: - print(f" {color('✗', Colors.RED)} Clean failed: {e}") + print(f" {color(mark('✗', 'x'), Colors.RED)} Clean failed: {e}") return False def verify_binary(module: Module) -> Optional[str]: @@ -490,6 +644,9 @@ def build_diagnostic_report( chunked: bool = False, message_blocker: Optional[str] = None, ) -> dict: + if logd_relpaths: + logd_relpaths = [repo_relative_path(path) for path in logd_relpaths] + diagnostic_logd: Optional[str | list[str]] if not logd_relpaths: diagnostic_logd = None @@ -500,7 +657,7 @@ def build_diagnostic_report( decrypt_target = logd_relpaths[0] if logd_relpaths and len(logd_relpaths) == 1 else None if logd_relpaths and len(logd_relpaths) > 1: - decrypt_target = str((DIAGNOSTIC_DIR / f"build-{commit_id}.logd").relative_to(ROOT)) + decrypt_target = repo_relative_path(DIAGNOSTIC_DIR / f"build-{commit_id}.logd") report = { "generated_at": datetime.datetime.now(datetime.timezone.utc).isoformat(), @@ -523,8 +680,8 @@ def build_diagnostic_report( "name": name, "status": "PASS" if success else "FAIL", "elapsed_seconds": round(elapsed, 3), - "artifact": binary, - "output": output, + "artifact": repo_relative_path(binary) if binary else None, + "output": redact_diagnostic_text(output), } for name, success, elapsed, output, binary in results ], @@ -534,12 +691,12 @@ def build_diagnostic_report( + "Maintainers may ask you to remove these diagnostic artifacts before merging." ), } - return report + return sanitize_diagnostic_value(report) def write_diagnostic_report(metadata_path: Path, report: dict) -> None: metadata_path.write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8") - print(f" {color('✓', Colors.GREEN)} {metadata_path.relative_to(ROOT)} created") + print(f" {color(mark('✓', '+'), Colors.GREEN)} {metadata_path.relative_to(ROOT)} created") def commit_diagnostic_artifacts(paths: list[Path], commit_id: str) -> bool: @@ -597,7 +754,7 @@ def generate_logd( ) -> bool: logd_path, metadata_path, commit_id = diagnostic_paths_for_commit() display_logd = logd_path.relative_to(ROOT) - print(f"\n {color('▸', Colors.CYAN)} Finalizing diagnostics for {color(str(display_logd), Colors.BOLD)}...") + print(f"\n {color(mark('▸', '>'), Colors.CYAN)} Finalizing diagnostics for {color(str(display_logd), Colors.BOLD)}...") # Always write the JSON report first. The encrypted .logd is useful, but the # report is required even when the build failed before compilation started or @@ -607,7 +764,7 @@ def generate_logd( encryptly_bin = get_encryptly_bin() if encryptly_bin is None: error = f"encryptly binary not found ({encryptly_platform_help()}); cannot create {display_logd}" - print(f" {color('✗', Colors.RED)} {error}") + print(f" {color(mark('✗', 'x'), Colors.RED)} {error}") write_diagnostic_report( metadata_path, build_diagnostic_report( @@ -631,7 +788,7 @@ def generate_logd( safe_dir.mkdir(parents=True, exist_ok=True) (safe_dir / "system-info.txt").write_text( - collect_system_info(), encoding="utf-8" + redact_diagnostic_text(collect_system_info()), encoding="utf-8" ) summary_lines = [ @@ -647,7 +804,7 @@ def generate_logd( for name, success, elapsed, _, binary in results: summary_lines.append( f" {name}: {'PASS' if success else 'FAIL'} ({elapsed:.2f}s)" - f"{f' [{binary}]' if binary else ''}" + f"{f' [{repo_relative_path(binary)}]' if binary else ''}" ) (safe_dir / "build-summary.txt").write_text( "\n".join(summary_lines), encoding="utf-8" @@ -660,9 +817,9 @@ def generate_logd( f"{'=' * 50}" ) if binary: - log_lines.append(f"artifact: {binary}") + log_lines.append(f"artifact: {repo_relative_path(binary)}") if output: - log_lines.append(output) + log_lines.append(redact_diagnostic_text(output)) (safe_dir / "build.log").write_text("\n".join(log_lines), encoding="utf-8") sr = subprocess.run( @@ -683,7 +840,7 @@ def generate_logd( if sr.returncode != 0: error = sr.stderr.strip() or sr.stdout.strip() or "encryptly pack failed" print( - f" {color('✗', Colors.RED)} {logd_path.relative_to(ROOT)} creation failed: " + f" {color(mark('✗', 'x'), Colors.RED)} {logd_path.relative_to(ROOT)} creation failed: " f"{error}" ) if logd_path.exists(): @@ -703,8 +860,8 @@ def generate_logd( safe_pw = sr.stdout.strip() logd_files = split_diagnostic_logd(logd_path) - logd_relpaths = [str(path.relative_to(ROOT)) for path in logd_files] - decrypt_target = logd_relpaths[0] if len(logd_relpaths) == 1 else str(logd_path.relative_to(ROOT)) + logd_relpaths = [repo_relative_path(path) for path in logd_files] + decrypt_target = logd_relpaths[0] if len(logd_relpaths) == 1 else repo_relative_path(logd_path) write_diagnostic_report( metadata_path, build_diagnostic_report( @@ -719,12 +876,13 @@ def generate_logd( for path in logd_files: size_kb = path.stat().st_size / 1024.0 print( - f" {color('✓', Colors.GREEN)} {path.relative_to(ROOT)} created " + f" {color(mark('✓', '+'), Colors.GREEN)} {path.relative_to(ROOT)} created " f"({size_kb:.1f} KiB)" ) + validate_diagnostic_pair(metadata_path, expected_logd_paths=logd_files) if len(logd_files) > 1: print( - f" {color('✓', Colors.GREEN)} split oversized diagnostic log into " + f" {color(mark('✓', '+'), Colors.GREEN)} split oversized diagnostic log into " f"{len(logd_files)} chunks of at most {DIAGNOSTIC_CHUNK_SIZE // (1024 * 1024)} MiB" ) if not commit_diagnostic_artifacts([metadata_path, *logd_files], commit_id): @@ -737,7 +895,7 @@ def generate_logd( print(f" diagnostic log file(s) and metadata file with this password.") if len(logd_files) > 1: print(f" Reassemble chunks in order before unpacking:") - print(f" cat {' '.join(logd_relpaths)} > {logd_path.relative_to(ROOT)}") + print(f" cat {' '.join(logd_relpaths)} > {repo_relative_path(logd_path)}") print(f" {color(safe_pw, Colors.CYAN)}") print(f" {color(f'encryptly unpack {decrypt_target} --password {safe_pw}', Colors.GRAY)}") return True @@ -755,13 +913,13 @@ def print_summary(results: list[tuple[str, bool, float, str, Optional[str]]]): total_time = sum(t for _, _, t, _, _ in results) for name, success, elapsed, output, binary in results: - status_icon = color("✓", Colors.GREEN) if success else color("✗", Colors.RED) + status_icon = color(mark("✓", "+"), Colors.GREEN) if success else color(mark("✗", "x"), Colors.RED) status_text = color("PASS", Colors.GREEN) if success else color("FAIL", Colors.RED) time_str = f"{elapsed:.1f}s" if elapsed < 60 else f"{elapsed / 60:.1f}m" print(f"\n {status_icon} {color(name + ':', Colors.BOLD)} {status_text} ({time_str})") if binary: - print(f" artifact: {color(binary, Colors.GRAY)}") + print(f" artifact: {color(repo_relative_path(binary), Colors.GRAY)}") if not success and output: lines = output.strip().split("\n") @@ -769,7 +927,7 @@ def print_summary(results: list[tuple[str, bool, float, str, Optional[str]]]): for line in lines[-5:]: print(f" {color(line, Colors.GRAY)}") - print(f"\n {color('─' * 40, Colors.GRAY)}") + print(f"\n {color(rule(40), Colors.GRAY)}") print(f" {color('Total:', Colors.BOLD)} {total} modules, " f"{color(str(passed) + ' passed', Colors.GREEN)}, " f"{color(str(failed) + ' failed', Colors.RED)}, " @@ -831,14 +989,14 @@ def main(): print(f" {color('Checking prerequisites...', Colors.GRAY)}") missing = check_prerequisites() if missing: - print(f"\n {color('⚠ Some tools missing - will try anyway:', Colors.YELLOW)}") + print(f"\n {color(safe_text('⚠ Some tools missing - will try anyway:', 'WARNING Some tools missing - will try anyway:'), Colors.YELLOW)}") for m in missing: print(f" {m}") msg = "Not all modules will build. That's fine." print(f" {color(msg, Colors.GRAY)}") else: - print(f" {color('✓ All prerequisites found', Colors.GREEN)}") + print(f" {color(safe_text('✓ All prerequisites found', '+ All prerequisites found'), Colors.GREEN)}") if args.module == "all": selected = MODULES else: @@ -846,7 +1004,7 @@ def main(): selected = [m for m in MODULES if m.name in names] not_found = set(names) - {m.name for m in MODULES} if not_found: - print(f" {color('✗ Unknown modules:', Colors.RED)} {', '.join(not_found)}") + print(f" {color(safe_text('✗ Unknown modules:', 'x Unknown modules:'), Colors.RED)} {', '.join(not_found)}") print(f" Available: {', '.join(m.name for m in MODULES)}") return 1 @@ -871,7 +1029,7 @@ def main(): shutil.rmtree(artifact) else: artifact.unlink() - print(f" {color('▸', Colors.YELLOW)} Removed {artifact.relative_to(ROOT)}") + print(f" {color(mark('▸', '>'), Colors.YELLOW)} Removed {artifact.relative_to(ROOT)}") print(f"\n {color('Clean complete.', Colors.GREEN)}") return 0 diff --git a/tests/test_diagnostic_regression.py b/tests/test_diagnostic_regression.py new file mode 100644 index 00000000..3e0df395 --- /dev/null +++ b/tests/test_diagnostic_regression.py @@ -0,0 +1,299 @@ +import importlib.util +import json +import os +import tempfile +import unittest +import time +from pathlib import Path +from unittest import mock + + +REPO_ROOT = Path(__file__).resolve().parents[1] +BUILD_PY = REPO_ROOT / "build.py" + +spec = importlib.util.spec_from_file_location("build", BUILD_PY) +build = importlib.util.module_from_spec(spec) +assert spec.loader is not None +spec.loader.exec_module(build) + + +class DiagnosticRedactionTests(unittest.TestCase): + def test_metadata_paths_are_repo_relative_and_sensitive_values_are_redacted(self): + output = "\n".join( + [ + f"repo={build.ROOT}", + f"home={Path.home()}", + f"temp={tempfile.gettempdir()}", + f"machine={build.platform.node()}", + f"user={build.getpass.getuser()}", + ] + ) + artifact = build.ROOT / "backend" / "target" / "debug" / "backend" + + report = build.build_diagnostic_report( + [("backend", True, 1.25, output, str(artifact))], + "deadbeef", + logd_relpaths=["diagnostic/build-deadbeef.logd"], + password="test-password", + ) + + self.assertEqual(report["diagnostic_logd"], "diagnostic/build-deadbeef.logd") + self.assertEqual( + build.repo_relative_path(r"diagnostic\build-deadbeef.logd"), + "diagnostic/build-deadbeef.logd", + ) + self.assertEqual( + report["decrypt_command"], + "encryptly unpack diagnostic/build-deadbeef.logd --password test-password", + ) + self.assertEqual(report["modules"][0]["artifact"], "backend/target/debug/backend") + + encoded = json.dumps(report, sort_keys=True) + self.assertNotIn(str(build.ROOT), encoded) + self.assertNotIn(str(build.ROOT).replace("\\", "/"), encoded) + self.assertNotIn(str(Path.home()), encoded) + self.assertNotIn(str(Path.home()).replace("\\", "/"), encoded) + self.assertNotIn(tempfile.gettempdir(), encoded) + self.assertNotIn(build.platform.node(), encoded) + self.assertNotIn(build.getpass.getuser(), encoded) + + def test_chunked_decrypt_command_uses_forward_slash_paths(self): + report = build.build_diagnostic_report( + [("backend", True, 1.25, "", None)], + "deadbeef", + logd_relpaths=[ + r"diagnostic\build-deadbeef-part001.logd", + r"diagnostic\build-deadbeef-part002.logd", + ], + password="test-password", + chunked=True, + ) + + self.assertEqual( + report["diagnostic_logd"], + [ + "diagnostic/build-deadbeef-part001.logd", + "diagnostic/build-deadbeef-part002.logd", + ], + ) + self.assertEqual( + report["decrypt_command"], + "encryptly unpack diagnostic/build-deadbeef.logd --password test-password", + ) + self.assertNotIn("\\", json.dumps(report, sort_keys=True)) + + def test_logd_reference_must_match_generated_artifact(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + diagnostic_dir = root / "diagnostic" + diagnostic_dir.mkdir() + metadata_path = diagnostic_dir / "build-deadbeef.json" + logd_path = diagnostic_dir / "build-deadbeef.logd" + logd_path.write_bytes(b"logd") + metadata_path.write_text( + json.dumps({"diagnostic_logd": "diagnostic/build-deadbeef.logd"}), + encoding="utf-8", + ) + + with patched_diagnostic_root(root, diagnostic_dir): + build.validate_diagnostic_pair(metadata_path, expected_logd_paths=[logd_path]) + + def test_missing_json_fails_clearly(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + diagnostic_dir = root / "diagnostic" + metadata_path = diagnostic_dir / "missing.json" + + with patched_diagnostic_root(root, diagnostic_dir): + with self.assertRaisesRegex(build.DiagnosticValidationError, "metadata JSON missing"): + build.validate_diagnostic_pair(metadata_path) + + def test_missing_logd_fails_clearly(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + diagnostic_dir = root / "diagnostic" + diagnostic_dir.mkdir() + metadata_path = diagnostic_dir / "build-deadbeef.json" + metadata_path.write_text( + json.dumps({"diagnostic_logd": "diagnostic/build-deadbeef.logd"}), + encoding="utf-8", + ) + + with patched_diagnostic_root(root, diagnostic_dir): + with self.assertRaisesRegex(build.DiagnosticValidationError, "diagnostic \\.logd missing"): + build.validate_diagnostic_pair(metadata_path) + + def test_mismatched_logd_reference_fails_clearly(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + diagnostic_dir = root / "diagnostic" + diagnostic_dir.mkdir() + metadata_path = diagnostic_dir / "build-deadbeef.json" + actual_logd = diagnostic_dir / "build-deadbeef.logd" + expected_logd = diagnostic_dir / "build-cafebabe.logd" + actual_logd.write_bytes(b"logd") + expected_logd.write_bytes(b"logd") + metadata_path.write_text( + json.dumps({"diagnostic_logd": "diagnostic/build-deadbeef.logd"}), + encoding="utf-8", + ) + + with patched_diagnostic_root(root, diagnostic_dir): + with self.assertRaisesRegex(build.DiagnosticValidationError, "diagnostic_logd mismatch"): + build.validate_diagnostic_pair(metadata_path, expected_logd_paths=[expected_logd]) + + def test_windows_absolute_logd_reference_fails_clearly(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + diagnostic_dir = root / "diagnostic" + diagnostic_dir.mkdir() + metadata_path = diagnostic_dir / "build-deadbeef.json" + metadata_path.write_text( + json.dumps({"diagnostic_logd": r"C:\Users\builder\build-deadbeef.logd"}), + encoding="utf-8", + ) + + with patched_diagnostic_root(root, diagnostic_dir): + with self.assertRaisesRegex(build.DiagnosticValidationError, "repo-relative"): + build.validate_diagnostic_pair(metadata_path) + + def test_posix_absolute_logd_reference_fails_clearly_on_every_platform(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + diagnostic_dir = root / "diagnostic" + diagnostic_dir.mkdir() + metadata_path = diagnostic_dir / "build-deadbeef.json" + metadata_path.write_text( + json.dumps({"diagnostic_logd": "/tmp/build-deadbeef.logd"}), + encoding="utf-8", + ) + + with patched_diagnostic_root(root, diagnostic_dir): + with self.assertRaisesRegex(build.DiagnosticValidationError, "repo-relative"): + build.validate_diagnostic_pair(metadata_path) + + def test_empty_logd_list_entry_fails_clearly(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + diagnostic_dir = root / "diagnostic" + diagnostic_dir.mkdir() + metadata_path = diagnostic_dir / "build-deadbeef.json" + (diagnostic_dir / "build-deadbeef-part001.logd").write_bytes(b"logd") + metadata_path.write_text( + json.dumps({"diagnostic_logd": ["diagnostic/build-deadbeef-part001.logd", ""]}), + encoding="utf-8", + ) + + with patched_diagnostic_root(root, diagnostic_dir): + with self.assertRaisesRegex(build.DiagnosticValidationError, "non-empty"): + build.validate_diagnostic_pair(metadata_path) + + def test_chunked_logd_reference_requires_every_part(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + diagnostic_dir = root / "diagnostic" + diagnostic_dir.mkdir() + metadata_path = diagnostic_dir / "build-deadbeef.json" + (diagnostic_dir / "build-deadbeef-part001.logd").write_bytes(b"logd") + metadata_path.write_text( + json.dumps( + { + "diagnostic_logd": [ + "diagnostic/build-deadbeef-part001.logd", + "diagnostic/build-deadbeef-part002.logd", + ] + } + ), + encoding="utf-8", + ) + + with patched_diagnostic_root(root, diagnostic_dir): + with self.assertRaisesRegex(build.DiagnosticValidationError, "part002"): + build.validate_diagnostic_pair(metadata_path) + + def test_external_artifact_path_is_reduced_to_filename(self): + outside_artifact = Path(tempfile.gettempdir()) / "outside" / "service.bin" + report = build.build_diagnostic_report( + [("backend", True, 1.25, "", str(outside_artifact))], + "deadbeef", + logd_relpaths=["diagnostic/build-deadbeef.logd"], + password="test-password", + ) + + self.assertEqual(report["modules"][0]["artifact"], "external/service.bin") + self.assertNotIn(tempfile.gettempdir(), json.dumps(report, sort_keys=True)) + + def test_non_utf8_output_uses_ascii_fallbacks(self): + fake_stdout = FakeStdout("gbk") + with mock.patch.object(build.sys, "stdout", fake_stdout): + warning = build.safe_text( + "\u26a0 Some tools missing - will try anyway:", + "WARNING Some tools missing - will try anyway:", + ) + status = build.mark("\u2713", "+") + separator = build.rule(8) + + warning.encode("gbk") + status.encode("gbk") + separator.encode("gbk") + self.assertEqual(warning, "WARNING Some tools missing - will try anyway:") + self.assertEqual(status, "+") + self.assertEqual(separator, "--------") + + def test_frontend_npm_install_missing_returns_failure(self): + with tempfile.TemporaryDirectory() as tmp: + module = build.Module( + name="frontend", + language="TypeScript", + dir=Path(tmp), + build_cmd=["npm", "run", "build"], + clean_cmd=[], + ) + + def fake_run(*args, **kwargs): + raise FileNotFoundError("npm") + + with mock.patch.object(build.subprocess, "run", side_effect=fake_run): + with mock.patch.object(time, "time", side_effect=[100.0, 101.25]): + success, elapsed, output = build.build_module(module) + + self.assertFalse(success) + self.assertEqual(elapsed, 1.25) + self.assertIn("npm install command not found", output) + + def test_engine_cmake_missing_returns_failure(self): + with tempfile.TemporaryDirectory() as tmp: + module = build.Module( + name="engine", + language="C++", + dir=Path(tmp), + build_cmd=["cmake", "--build", "build"], + clean_cmd=[], + ) + + def fake_run(*args, **kwargs): + raise FileNotFoundError("cmake") + + with mock.patch.object(build.subprocess, "run", side_effect=fake_run): + with mock.patch.object(time, "time", side_effect=[200.0, 202.5]): + success, elapsed, output = build.build_module(module) + + self.assertFalse(success) + self.assertEqual(elapsed, 2.5) + self.assertIn("CMake configure command not found", output) + + +def patched_diagnostic_root(root: Path, diagnostic_dir: Path): + return mock.patch.multiple(build, ROOT=root, DIAGNOSTIC_DIR=diagnostic_dir) + + +class FakeStdout: + def __init__(self, encoding: str): + self.encoding = encoding + + def isatty(self): + return False + + +if __name__ == "__main__": + unittest.main() From d64c8115a8cab204025a74fe076c49c1a6143ae3 Mon Sep 17 00:00:00 2001 From: fengyangxxx <356261005@qq.com> Date: Fri, 19 Jun 2026 19:29:28 +0000 Subject: [PATCH 2/2] Add build diagnostics for 0c8d9252 --- diagnostic/build-0c8d9252.json | 87 +++++++++++++++++++++++++++++++++ diagnostic/build-0c8d9252.logd | Bin 0 -> 39060 bytes 2 files changed, 87 insertions(+) create mode 100644 diagnostic/build-0c8d9252.json create mode 100644 diagnostic/build-0c8d9252.logd diff --git a/diagnostic/build-0c8d9252.json b/diagnostic/build-0c8d9252.json new file mode 100644 index 00000000..617d53c3 --- /dev/null +++ b/diagnostic/build-0c8d9252.json @@ -0,0 +1,87 @@ +{ + "generated_at": "2026-06-19T19:29:25.166954+00:00", + "commit": "0c8d9252", + "diagnostic_logd": "diagnostic/build-0c8d9252.logd", + "diagnostic_logd_error": null, + "message_blocker": null, + "chunked": false, + "chunk_size_bytes": null, + "password": "a09244f378b549c6b6e6", + "decrypt_command": "encryptly unpack diagnostic/build-0c8d9252.logd --password a09244f378b549c6b6e6", + "total_modules": 10, + "passed": 7, + "failed": 3, + "modules": [ + { + "name": "backend", + "status": "PASS", + "elapsed_seconds": 134.992, + "artifact": "backend/target", + "output": "\u001b[1m\u001b[92m Updating\u001b[0m crates.io index\n\u001b[1m\u001b[92m Downloading\u001b[0m crates ...\n\u001b[1m\u001b[92m Downloaded\u001b[0m anstyle-parse v1.0.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m anstyle v1.0.14\n\u001b[1m\u001b[92m Downloaded\u001b[0m anstream v1.0.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m aho-corasick v1.1.4\n\u001b[1m\u001b[92m Downloaded\u001b[0m autocfg v1.5.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m errno v0.3.14\n\u001b[1m\u001b[92m Downloaded\u001b[0m colorchoice v1.0.5\n\u001b[1m\u001b[92m Downloaded\u001b[0m block-buffer v0.10.4\n\u001b[1m\u001b[92m Downloaded\u001b[0m either v1.16.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m cfg-if v1.0.4\n\u001b[1m\u001b[92m Downloaded\u001b[0m anyhow v1.0.102\n\u001b[1m\u001b[92m Downloaded\u001b[0m bitflags v2.13.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m futures-executor v0.3.32\n\u001b[1m\u001b[92m Downloaded\u001b[0m clap_builder v4.6.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m http-body v1.0.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m hyper-tls v0.6.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m async-trait v0.1.89\n\u001b[1m\u001b[92m Downloaded\u001b[0m indexmap v2.14.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m getrandom v0.4.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m prost-build v0.13.5\n\u001b[1m\u001b[92m Downloaded\u001b[0m icu_provider v2.2.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m atomic-waker v1.1.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m icu_normalizer_data v2.2.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m icu_collections v2.2.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m potential_utf v0.1.5\n\u001b[1m\u001b[92m Downloaded\u001b[0m find-msvc-tools v0.1.9\n\u001b[1m\u001b[92m Downloaded\u001b[0m crossbeam-utils v0.8.21\n\u001b[1m\u001b[92m Downloaded\u001b[0m hashbrown v0.17.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m idna_adapter v1.2.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m clap_derive v4.6.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m once_cell v1.21.4\n\u001b[1m\u001b[92m Downloaded\u001b[0m mime v0.3.17\n\u001b[1m\u001b[92m Downloaded\u001b[0m foreign-types v0.3.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m lazy_static v1.5.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m hyper-rustls v0.27.9\n\u001b[1m\u001b[92m Downloaded\u001b[0m futures v0.3.32\n\u001b[1m\u001b[92m Downloaded\u001b[0m idna v1.1.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m form_urlencoded v1.2.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m digest v0.10.7\n\u001b[1m\u001b[92m Downloaded\u001b[0m futures-core v0.3.32\n\u001b[1m\u001b[92m Downloaded\u001b[0m fastrand v2.4.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m crypto-common v0.1.7\n\u001b[1m\u001b[92m Downloaded\u001b[0m prettyplease v0.2.37\n\u001b[1m\u001b[92m Downloaded\u001b[0m displaydoc v0.2.6\n\u001b[1m\u001b[92m Downloaded\u001b[0m futures-task v0.3.32\n\u001b[1m\u001b[92m Downloaded\u001b[0m is_terminal_polyfill v1.70.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m openssl-probe v0.2.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m openssl-macros v0.1.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m equivalent v1.0.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m percent-encoding v2.3.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m serde_urlencoded v0.7.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m stable_deref_trait v1.2.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m multimap v0.10.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m prost-derive v0.13.5\n\u001b[1m\u001b[92m Downloaded\u001b[0m parking_lot_core v0.9.12\n\u001b[1m\u001b[92m Downloaded\u001b[0m nu-ansi-term v0.50.3\n\u001b[1m\u001b[92m Downloaded\u001b[0m prost v0.13.5\n\u001b[1m\u001b[92m Downloaded\u001b[0m pin-project-lite v0.2.17\n\u001b[1m\u001b[92m Downloaded\u001b[0m slab v0.4.12\n\u001b[1m\u001b[92m Downloaded\u001b[0m num-traits v0.2.19\n\u001b[1m\u001b[92m Downloaded\u001b[0m tracing-serde v0.2.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m shlex v2.0.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m memchr v2.8.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m sha2 v0.10.9\n\u001b[1m\u001b[92m Downloaded\u001b[0m tokio-native-tls v0.3.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m prost-types v0.13.5\n\u001b[1m\u001b[92m Downloaded\u001b[0m icu_properties_data v2.2.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m strsim v0.11.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m proc-macro2 v1.0.106\n\u001b[1m\u001b[92m Downloaded\u001b[0m socket2 v0.6.4\n\u001b[1m\u001b[92m Downloaded\u001b[0m toml_write v0.1.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m tower-service v0.3.3\n\u001b[1m\u001b[92m Downloaded\u001b[0m tower-layer v0.3.3\n\u001b[1m\u001b[92m Downloaded\u001b[0m openssl v0.10.81\n\u001b[1m\u001b[92m Downloaded\u001b[0m tokio-macros v2.7.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m sync_wrapper v1.0.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m toml_datetime v0.6.11\n\u001b[1m\u001b[92m Downloaded\u001b[0m serde_core v1.0.228\n\u001b[1m\u001b[92m Downloaded\u001b[0m thiserror-impl v2.0.18\n\u001b[1m\u001b[92m Downloaded\u001b[0m thiserror v2.0.18\n\u001b[1m\u001b[92m Downloaded\u001b[0m synstructure v0.13.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m serde v1.0.228\n\u001b[1m\u001b[92m Downloaded\u001b[0m ryu v1.0.23\n\u001b[1m\u001b[92m Downloaded\u001b[0m encoding_rs v0.8.35\n\u001b[1m\u001b[92m Downloaded\u001b[0m petgraph v0.7.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m tracing-log v0.2.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m tempfile v3.27.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m sharded-slab v0.1.7\n\u001b[1m\u001b[92m Downloaded\u001b[0m zerofrom-derive v0.1.7\n\u001b[1m\u001b[92m Downloaded\u001b[0m zerovec-derive v0.11.3\n\u001b[1m\u001b[92m Downloaded\u001b[0m zmij v1.0.21\n\u001b[1m\u001b[92m Downloaded\u001b[0m tower v0.5.3\n\u001b[1m\u001b[92m Downloaded\u001b[0m yoke v0.8.3\n\u001b[1m\u001b[92m Downloaded\u001b[0m uuid v1.23.3\n\u001b[1m\u001b[92m Downloaded\u001b[0m zerotrie v0.2.4\n\u001b[1m\u001b[92m Downloaded\u001b[0m typenum v1.20.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m url v2.5.8\n\u001b[1m\u001b[92m Downloaded\u001b[0m zerovec v0.11.6\n\u001b[1m\u001b[92m Downloaded\u001b[0m tracing-subscriber v0.3.23\n\u001b[1m\u001b[92m Downloaded\u001b[0m tower-http v0.6.11\n\u001b[1m\u001b[92m Downloaded\u001b[0m winnow v0.7.15\n\u001b[1m\u001b[92m Downloaded\u001b[0m tokio-util v0.7.18\n\u001b[1m\u001b[92m Downloaded\u001b[0m unicode-ident v1.0.24\n\u001b[1m\u001b[92m Downloaded\u001b[0m vcpkg v0.2.15\n\u001b[1m\u001b[92m Downloaded\u001b[0m regex-syntax v0.8.11\n\u001b[1m\u001b[92m Downloaded\u001b[0m rustls v0.23.40\n\u001b[1m\u001b[92m Downloaded\u001b[0m syn v2.0.117\n\u001b[1m\u001b[92m Downloaded\u001b[0m serde_json v1.0.150\n\u001b[1m\u001b[92m Downloaded\u001b[0m rustix v1.1.4\n\u001b[1m\u001b[92m Downloaded\u001b[0m regex v1.12.4\n\u001b[1m\u001b[92m Downloaded\u001b[0m libc v0.2.186\n\u001b[1m\u001b[92m Downloaded\u001b[0m tracing v0.1.44\n\u001b[1m\u001b[92m Downloaded\u001b[0m zeroize v1.9.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m writeable v0.6.3\n\u001b[1m\u001b[92m Downloaded\u001b[0m untrusted v0.9.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m reqwest v0.12.28\n\u001b[1m\u001b[92m Downloaded\u001b[0m zerofrom v0.1.8\n\u001b[1m\u001b[92m Downloaded\u001b[0m regex-automata v0.4.14\n\u001b[1m\u001b[92m Downloaded\u001b[0m yoke-derive v0.8.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m want v0.3.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m version_check v0.9.5\n\u001b[1m\u001b[92m Downloaded\u001b[0m utf8parse v0.2.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m utf8_iter v1.0.4\n\u001b[1m\u001b[92m Downloaded\u001b[0m try-lock v0.2.5\n\u001b[1m\u001b[92m Downloaded\u001b[0m tracing-core v0.1.36\n\u001b[1m\u001b[92m Downloaded\u001b[0m toml_edit v0.22.27\n\u001b[1m\u001b[92m Downloaded\u001b[0m tracing-attributes v0.1.31\n\u001b[1m\u001b[92m Downloaded\u001b[0m tonic-build v0.12.3\n\u001b[1m\u001b[92m Downloaded\u001b[0m toml v0.8.23\n\u001b[1m\u001b[92m Downloaded\u001b[0m tokio-rustls v0.26.4\n\u001b[1m\u001b[92m Downloaded\u001b[0m tinystr v0.8.3\n\u001b[1m\u001b[92m Downloaded\u001b[0m thread_local v1.1.9\n\u001b[1m\u001b[92m Downloaded\u001b[0m smallvec v1.15.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m rustls-webpki v0.103.13\n\u001b[1m\u001b[92m Downloaded\u001b[0m chrono v0.4.45\n\u001b[1m\u001b[92m Downloaded\u001b[0m tokio v1.52.3\n\u001b[1m\u001b[92m Downloaded\u001b[0m pkg-config v0.3.33\n\u001b[1m\u001b[92m Downloaded\u001b[0m subtle v2.6.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m serde_derive v1.0.228\n\u001b[1m\u001b[92m Downloaded\u001b[0m hashbrown v0.14.5\n\u001b[1m\u001b[92m Downloaded\u001b[0m h2 v0.4.14\n\u001b[1m\u001b[92m Downloaded\u001b[0m itertools v0.14.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m hyper v1.10.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m rustls-pki-types v1.14.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m mio v1.2.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m http v1.4.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m hyper-util v0.1.20\n\u001b[1m\u001b[92m Downloaded\u001b[0m scopeguard v1.2.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m quote v1.0.45\n\u001b[1m\u001b[92m Downloaded\u001b[0m openssl-sys v0.9.117\n\u001b[1m\u001b[92m Downloaded\u001b[0m icu_normalizer v2.2.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m icu_properties v2.2.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m signal-hook-registry v1.4.8\n\u001b[1m\u001b[92m Downloaded\u001b[0m litemap v0.8.2\n\u001b[1m\u001b[92m Downloaded\u001b[0m iana-time-zone v0.1.65\n\u001b[1m\u001b[92m Downloaded\u001b[0m httparse v1.10.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m getrandom v0.2.17\n\u001b[1m\u001b[92m Downloaded\u001b[0m clap v4.6.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m cc v1.2.64\n\u001b[1m\u001b[92m Downloaded\u001b[0m parking_lot v0.12.5\n\u001b[1m\u001b[92m Downloaded\u001b[0m ipnet v2.12.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m native-tls v0.2.18\n\u001b[1m\u001b[92m Downloaded\u001b[0m lock_api v0.4.14\n\u001b[1m\u001b[92m Downloaded\u001b[0m matchers v0.2.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m serde_spanned v0.6.9\n\u001b[1m\u001b[92m Downloaded\u001b[0m heck v0.5.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m log v0.4.32\n\u001b[1m\u001b[92m Downloaded\u001b[0m icu_locale_core v2.2.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m http-body-util v0.1.3\n\u001b[1m\u001b[92m Downloaded\u001b[0m ring v0.17.14\n\u001b[1m\u001b[92m Downloaded\u001b[0m itoa v1.0.18\n\u001b[1m\u001b[92m Downloaded\u001b[0m cpufeatures v0.2.17\n\u001b[1m\u001b[92m Downloaded\u001b[0m clap_lex v1.1.0\n\u001b[1m\u001b[92m Downloaded\u001b[0m futures-util v0.3.32\n\u001b[1m\u001b[92m Downloaded\u001b[0m futures-macro v0.3.32\n\u001b[1m\u001b[92m Downloaded\u001b[0m futures-io v0.3.32\n\u001b[1m\u001b[92m Downloaded\u001b[0m base64 v0.22.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m generic-array v0.14.7\n\u001b[1m\u001b[92m Downloaded\u001b[0m linux-raw-sys v0.12.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m fnv v1.0.7\n\u001b[1m\u001b[92m Downloaded\u001b[0m futures-sink v0.3.32\n\u001b[1m\u001b[92m Downloaded\u001b[0m futures-channel v0.3.32\n\u001b[1m\u001b[92m Downloaded\u001b[0m anstyle-query v1.1.5\n\u001b[1m\u001b[92m Downloaded\u001b[0m foreign-types-shared v0.1.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m fixedbitset v0.5.7\n\u001b[1m\u001b[92m Downloaded\u001b[0m dashmap v6.2.1\n\u001b[1m\u001b[92m Downloaded\u001b[0m bytes v1.11.1\n\u001b[1m\u001b[92m Compiling\u001b[0m libc v0.2.186\n\u001b[1m\u001b[92m Compiling\u001b[0m serde_core v1.0.228\n\u001b[1m\u001b[92m Compiling\u001b[0m serde v1.0.228\n\u001b[1m\u001b[92m Compiling\u001b[0m synstructure v0.13.2\n\u001b[1m\u001b[92m Compiling\u001b[0m zerovec-derive v0.11.3\n\u001b[1m\u001b[92m Compiling\u001b[0m displaydoc v0.2.6\n\u001b[1m\u001b[92m Compiling\u001b[0m tokio-macros v2.7.0\n\u001b[1m\u001b[92m Compiling\u001b[0m serde_derive v1.0.228\n\u001b[1m\u001b[92m Compiling\u001b[0m futures-macro v0.3.32\n\u001b[1m\u001b[92m Compiling\u001b[0m openssl-sys v0.9.117\n\u001b[1m\u001b[92m Compiling\u001b[0m tracing-attributes v0.1.31\n\u001b[1m\u001b[92m Compiling\u001b[0m openssl-macros v0.1.1\n\u001b[1m\u001b[92m Compiling\u001b[0m generic-array v0.14.7\n\u001b[1m\u001b[92m Compiling\u001b[0m zmij v1.0.21\n\u001b[1m\u001b[92m Compiling\u001b[0m regex-automata v0.4.14\n\u001b[1m\u001b[92m Compiling\u001b[0m getrandom v0.4.2\n\u001b[1m\u001b[92m Compiling\u001b[0m crossbeam-utils v0.8.21\n\u001b[1m\u001b[92m Compiling\u001b[0m openssl v0.10.81\n\u001b[1m\u001b[92m Compiling\u001b[0m native-tls v0.2.18\n\u001b[1m\u001b[92m Compiling\u001b[0m num-traits v0.2.19\n\u001b[1m\u001b[92m Compiling\u001b[0m strsim v0.11.1\n\u001b[1m\u001b[92m Compiling\u001b[0m ryu v1.0.23\n\u001b[1m\u001b[92m Compiling\u001b[0m block-buffer v0.10.4\n\u001b[1m\u001b[92m Compiling\u001b[0m crypto-common v0.1.7\n\u001b[1m\u001b[92m Compiling\u001b[0m winnow v0.7.15\n\u001b[1m\u001b[92m Compiling\u001b[0m heck v0.5.0\n\u001b[1m\u001b[92m Compiling\u001b[0m toml_write v0.1.2\n\u001b[1m\u001b[92m Compiling\u001b[0m thiserror v2.0.18\n\u001b[1m\u001b[92m Compiling\u001b[0m digest v0.10.7\n\u001b[1m\u001b[92m Compiling\u001b[0m parking_lot_core v0.9.12\n\u001b[1m\u001b[92m Compiling\u001b[0m errno v0.3.14\n\u001b[1m\u001b[92m Compiling\u001b[0m zerofrom-derive v0.1.7\n\u001b[1m\u001b[92m Compiling\u001b[0m yoke-derive v0.8.2\n\u001b[1m\u001b[92m Compiling\u001b[0m mio v1.2.1\n\u001b[1m\u001b[92m Compiling\u001b[0m socket2 v0.6.4\n\u001b[1m\u001b[92m Compiling\u001b[0m futures-util v0.3.32\n\u001b[1m\u001b[92m Compiling\u001b[0m signal-hook-registry v1.4.8\n\u001b[1m\u001b[92m Compiling\u001b[0m parking_lot v0.12.5\n\u001b[1m\u001b[92m Compiling\u001b[0m clap_derive v4.6.1\n\u001b[1m\u001b[92m Compiling\u001b[0m serde_json v1.0.150\n\u001b[1m\u001b[92m Compiling\u001b[0m tracing v0.1.44\n\u001b[1m\u001b[92m Compiling\u001b[0m tokio v1.52.3\n\u001b[1m\u001b[92m Compiling\u001b[0m clap_builder v4.6.0\n\u001b[1m\u001b[92m Compiling\u001b[0m sharded-slab v0.1.7\n\u001b[1m\u001b[92m Compiling\u001b[0m rustls-pki-types v1.14.1\n\u001b[1m\u001b[92m Compiling\u001b[0m anyhow v1.0.102\n\u001b[1m\u001b[92m Compiling\u001b[0m matchers v0.2.0\n\u001b[1m\u001b[92m Compiling\u001b[0m thiserror-impl v2.0.18\n\u001b[1m\u001b[92m Compiling\u001b[0m tracing-log v0.2.0\n\u001b[1m\u001b[92m Compiling\u001b[0m thread_local v1.1.9\n\u001b[1m\u001b[92m Compiling\u001b[0m zerofrom v0.1.8\n\u001b[1m\u001b[92m Compiling\u001b[0m encoding_rs v0.8.35\n\u001b[1m\u001b[92m Compiling\u001b[0m mime v0.3.17\n\u001b[1m\u001b[92m Compiling\u001b[0m yoke v0.8.3\n\u001b[1m\u001b[92m Compiling\u001b[0m iana-time-zone v0.1.65\n\u001b[1m\u001b[92m Compiling\u001b[0m cpufeatures v0.2.17\n\u001b[1m\u001b[92m Compiling\u001b[0m nu-ansi-term v0.50.3\n\u001b[1m\u001b[92m Compiling\u001b[0m hashbrown v0.14.5\n\u001b[1m\u001b[92m Compiling\u001b[0m sha2 v0.10.9\n\u001b[1m\u001b[92m Compiling\u001b[0m zerovec v0.11.6\n\u001b[1m\u001b[92m Compiling\u001b[0m zerotrie v0.2.4\n\u001b[1m\u001b[92m Compiling\u001b[0m serde_spanned v0.6.9\n\u001b[1m\u001b[92m Compiling\u001b[0m toml_datetime v0.6.11\n\u001b[1m\u001b[92m Compiling\u001b[0m tracing-serde v0.2.0\n\u001b[1m\u001b[92m Compiling\u001b[0m serde_urlencoded v0.7.1\n\u001b[1m\u001b[92m Compiling\u001b[0m toml_edit v0.22.27\n\u001b[1m\u001b[92m Compiling\u001b[0m tinystr v0.8.3\n\u001b[1m\u001b[92m Compiling\u001b[0m potential_utf v0.1.5\n\u001b[1m\u001b[92m Compiling\u001b[0m futures-executor v0.3.32\n\u001b[1m\u001b[92m Compiling\u001b[0m tracing-subscriber v0.3.23\n\u001b[1m\u001b[92m Compiling\u001b[0m dashmap v6.2.1\n\u001b[1m\u001b[92m Compiling\u001b[0m chrono v0.4.45\n\u001b[1m\u001b[92m Compiling\u001b[0m clap v4.6.1\n\u001b[1m\u001b[92m Compiling\u001b[0m icu_collections v2.2.0\n\u001b[1m\u001b[92m Compiling\u001b[0m icu_locale_core v2.2.0\n\u001b[1m\u001b[92m Compiling\u001b[0m futures v0.3.32\n\u001b[1m\u001b[92m Compiling\u001b[0m regex v1.12.4\n\u001b[1m\u001b[92m Compiling\u001b[0m uuid v1.23.3\n\u001b[1m\u001b[92m Compiling\u001b[0m async-trait v0.1.89\n\u001b[1m\u001b[92m Compiling\u001b[0m icu_provider v2.2.0\n\u001b[1m\u001b[92m Compiling\u001b[0m toml v0.8.23\n\u001b[1m\u001b[92m Compiling\u001b[0m tokio-util v0.7.18\n\u001b[1m\u001b[92m Compiling\u001b[0m tower v0.5.3\n\u001b[1m\u001b[92m Compiling\u001b[0m tokio-native-tls v0.3.1\n\u001b[1m\u001b[92m Compiling\u001b[0m icu_properties v2.2.0\n\u001b[1m\u001b[92m Compiling\u001b[0m icu_normalizer v2.2.0\n\u001b[1m\u001b[92m Compiling\u001b[0m h2 v0.4.14\n\u001b[1m\u001b[92m Compiling\u001b[0m idna_adapter v1.2.2\n\u001b[1m\u001b[92m Compiling\u001b[0m hyper v1.10.1\n\u001b[1m\u001b[92m Compiling\u001b[0m idna v1.1.0\n\u001b[1m\u001b[92m Compiling\u001b[0m url v2.5.8\n\u001b[1m\u001b[92m Compiling\u001b[0m hyper-util v0.1.20\n\u001b[1m\u001b[92m Compiling\u001b[0m tower-http v0.6.11\n\u001b[1m\u001b[92m Compiling\u001b[0m hyper-tls v0.6.0\n\u001b[1m\u001b[92m Compiling\u001b[0m reqwest v0.12.28\n\u001b[1m\u001b[92m Compiling\u001b[0m tent-backend v0.1.0 (/backend)\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused import: `warn`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/ai/embeddings.rs:28:28\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m28\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use tracing::{debug, info, warn};\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m\n \u001b[1m\u001b[94m= \u001b[0m\u001b[1mnote\u001b[0m: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused import: `error`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/ai/inference.rs:25:22\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m25\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use tracing::{debug, error, info, warn};\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused imports: `error` and `warn`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/ai/mod.rs:40:22\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m40\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use tracing::{debug, error, info, warn};\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^\u001b[0m \u001b[1m\u001b[33m^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused imports: `c_int` and `c_uint`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/bridge.rs:38:20\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m38\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use std::os::raw::{c_int, c_uint, c_ulong};\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^\u001b[0m \u001b[1m\u001b[33m^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused import: `std::ffi::CString`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/legacy.rs:35:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m35\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use std::ffi::CString;\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused import: `c_char`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/legacy.rs:36:20\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m36\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use std::os::raw::{c_char, c_ulong};\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused import: `CStr`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/types.rs:27:16\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m27\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use std::ffi::{CStr, CString};\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused imports: `c_double` and `c_long`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/types.rs:29:28\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m29\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use std::os::raw::{c_char, c_double, c_int, c_uint, c_void, c_long, c_ulong};\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^\u001b[0m \u001b[1m\u001b[33m^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused import: `AtomicBool`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/legacy/deprecations.rs:14:25\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m14\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering};\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused imports: `EntityKind` and `legacy_normalize_phone_number`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/legacy/v1_compat.rs:8:47\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m8\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use crate::legacy::deprecations::{LegacyUuid, EntityKind, LegacyPagination, legacy_normalize_phone_number};\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused import: `super::ProtocolError`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/protocol/validate.rs:27:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m27\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use super::ProtocolError;\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused import: `MAX_MESSAGE_SIZE`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/protocol/codec.rs:25:38\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m25\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use crate::protocol::{ProtocolError, MAX_MESSAGE_SIZE, MIN_COMPATIBLE_VERSION, PROTOCOL_VERSION};\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused import: `Write`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/protocol/codec.rs:26:29\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m26\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use std::io::{Cursor, Read, Write};\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused import: `Ordering`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/protocol/rpc.rs:25:36\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m25\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use std::sync::atomic::{AtomicU64, Ordering};\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused imports: `Duration` and `Instant`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/protocol/rpc.rs:27:17\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m27\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use std::time::{Duration, Instant};\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^\u001b[0m \u001b[1m\u001b[33m^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused imports: `Deserialize` and `Serialize`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/protocol/rpc.rs:28:13\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m28\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use serde::{Deserialize, Serialize};\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused import: `MAX_MESSAGE_SIZE`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/protocol/rpc.rs:31:28\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m31\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use super::{ProtocolError, MAX_MESSAGE_SIZE, DEFAULT_TIMEOUT_MS};\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused imports: `FrameDecoder` and `FrameEncoder`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/protocol/rpc.rs:32:27\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m32\u001b[0m \u001b[1m\u001b[94m|\u001b[0m use super::codec::{Frame, FrameEncoder, FrameDecoder, FLAG_REQUIRES_ACK};\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: use of deprecated unit variant `legacy::deprecations::EntityKind::Team`: Teams are now Organizations. Use Organization instead.\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/legacy/deprecations.rs:244:25\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m244\u001b[0m \u001b[1m\u001b[94m|\u001b[0m EntityKind::Team => \"org\", // Legacy mapping\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m\n \u001b[1m\u001b[94m= \u001b[0m\u001b[1mnote\u001b[0m: `#[warn(deprecated)]` on by default\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: use of deprecated unit variant `legacy::deprecations::EntityKind::Project`: Projects were removed in the Platform v2 migration\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/legacy/deprecations.rs:245:25\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m245\u001b[0m \u001b[1m\u001b[94m|\u001b[0m EntityKind::Project => \"workspace\", // Legacy mapping\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: use of deprecated unit variant `legacy::deprecations::EntityKind::Team`: Teams are now Organizations. Use Organization instead.\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/legacy/deprecations.rs:266:25\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m266\u001b[0m \u001b[1m\u001b[94m|\u001b[0m EntityKind::Team\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: use of deprecated unit variant `legacy::deprecations::EntityKind::Project`: Projects were removed in the Platform v2 migration\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/legacy/deprecations.rs:267:31\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m267\u001b[0m \u001b[1m\u001b[94m|\u001b[0m | EntityKind::Project\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: variable does not need to be mutable\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/bridge.rs:317:13\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m317\u001b[0m \u001b[1m\u001b[94m|\u001b[0m let mut buffer = unsafe { &mut *c_buffer };\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m----\u001b[0m\u001b[1m\u001b[33m^^^^^^\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m|\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94mhelp: remove this `mut`\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m\n \u001b[1m\u001b[94m= \u001b[0m\u001b[1mnote\u001b[0m: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused variable: `initialized`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/bridge.rs:440:13\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m440\u001b[0m \u001b[1m\u001b[94m|\u001b[0m let initialized = Arc::new(AtomicBool::new(true));\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^\u001b[0m \u001b[1m\u001b[33mhelp: if this is intentional, prefix it with an underscore: `_initialized`\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m\n \u001b[1m\u001b[94m= \u001b[0m\u001b[1mnote\u001b[0m: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: variable does not need to be mutable\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/legacy.rs:267:13\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m267\u001b[0m \u001b[1m\u001b[94m|\u001b[0m let mut buffer = unsafe { &mut *c_buffer };\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m----\u001b[0m\u001b[1m\u001b[33m^^^^^^\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m|\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94mhelp: remove this `mut`\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused variable: `value`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/legacy/deprecations.rs:508:15\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m508\u001b[0m \u001b[1m\u001b[94m|\u001b[0m for (key, value) in configs {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^\u001b[0m \u001b[1m\u001b[33mhelp: if this is intentional, prefix it with an underscore: `_value`\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: unused variable: `obj`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/protocol/validate.rs:282:25\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m282\u001b[0m \u001b[1m\u001b[94m|\u001b[0m if let Some(obj) = value.as_object() {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^\u001b[0m \u001b[1m\u001b[33mhelp: if this is intentional, prefix it with an underscore: `_obj`\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: type `BridgeStats` is more private than the item `ConnectorBridge::stats`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/bridge.rs:415:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m415\u001b[0m \u001b[1m\u001b[94m|\u001b[0m pub fn stats(&self) -> BridgeStats {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m \u001b[1m\u001b[33mmethod `ConnectorBridge::stats` is reachable at visibility `pub`\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[92mnote\u001b[0m: but type `BridgeStats` is only usable at visibility `pub(self)`\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/bridge.rs:225:1\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m225\u001b[0m \u001b[1m\u001b[94m|\u001b[0m struct BridgeStats {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[92m^^^^^^^^^^^^^^^^^^\u001b[0m\n \u001b[1m\u001b[94m= \u001b[0m\u001b[1mnote\u001b[0m: `#[warn(private_interfaces)]` on by default\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: type `CircuitState` is more private than the item `ConnectorBridge::circuit_state`\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/bridge.rs:423:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m423\u001b[0m \u001b[1m\u001b[94m|\u001b[0m pub fn circuit_state(&self) -> CircuitState {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m \u001b[1m\u001b[33mmethod `ConnectorBridge::circuit_state` is reachable at visibility `pub`\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[92mnote\u001b[0m: but type `CircuitState` is only usable at visibility `pub(self)`\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/bridge.rs:79:1\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m 79\u001b[0m \u001b[1m\u001b[94m|\u001b[0m enum CircuitState {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[92m^^^^^^^^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: constant `NCP_TEMPERATURE` is never used\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/ai/mod.rs:53:7\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m53\u001b[0m \u001b[1m\u001b[94m|\u001b[0m const NCP_TEMPERATURE: f64 = 0.42;\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^^^\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m\n \u001b[1m\u001b[94m= \u001b[0m\u001b[1mnote\u001b[0m: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: constant `MIN_CONFIDENCE_THRESHOLD` is never used\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/ai/mod.rs:61:7\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m61\u001b[0m \u001b[1m\u001b[94m|\u001b[0m const MIN_CONFIDENCE_THRESHOLD: f64 = 0.65;\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: constant `MAX_INFERENCE_RETRIES` is never used\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/ai/mod.rs:65:7\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m65\u001b[0m \u001b[1m\u001b[94m|\u001b[0m const MAX_INFERENCE_RETRIES: u32 = 5;\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: fields `discovery`, `broker`, and `registry` are never read\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/ai/mod.rs:173:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m171\u001b[0m \u001b[1m\u001b[94m|\u001b[0m pub struct AiOrchestrator {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m--------------\u001b[0m \u001b[1m\u001b[94mfields in this struct\u001b[0m\n\u001b[1m\u001b[94m172\u001b[0m \u001b[1m\u001b[94m|\u001b[0m /// Reference to the service discovery subsystem\n\u001b[1m\u001b[94m173\u001b[0m \u001b[1m\u001b[94m|\u001b[0m discovery: Arc>,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^\u001b[0m\n\u001b[1m\u001b[94m174\u001b[0m \u001b[1m\u001b[94m|\u001b[0m /// Reference to the message broker subsystem\n\u001b[1m\u001b[94m175\u001b[0m \u001b[1m\u001b[94m|\u001b[0m broker: Arc>,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^\u001b[0m\n\u001b[1m\u001b[94m176\u001b[0m \u001b[1m\u001b[94m|\u001b[0m /// Reference to the service registry subsystem\n\u001b[1m\u001b[94m177\u001b[0m \u001b[1m\u001b[94m|\u001b[0m registry: Arc>,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: field `window_start` is never read\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/ai/embeddings.rs:661:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m658\u001b[0m \u001b[1m\u001b[94m|\u001b[0m pub struct ContextWindowManager {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m--------------------\u001b[0m \u001b[1m\u001b[94mfield in this struct\u001b[0m\n\u001b[1m\u001b[94m...\u001b[0m\n\u001b[1m\u001b[94m661\u001b[0m \u001b[1m\u001b[94m|\u001b[0m window_start: Instant,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: constant `MAX_RETRIES` is never used\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/ai/inference.rs:41:7\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m41\u001b[0m \u001b[1m\u001b[94m|\u001b[0m const MAX_RETRIES: u32 = 3;\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: constant `RETRY_BASE_DELAY_MS` is never used\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/ai/inference.rs:44:7\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m44\u001b[0m \u001b[1m\u001b[94m|\u001b[0m const RETRY_BASE_DELAY_MS: u64 = 1000;\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: fields `api_key`, `base_url`, and `client` are never read\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/ai/inference.rs:453:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m452\u001b[0m \u001b[1m\u001b[94m|\u001b[0m pub struct AnthropicClient {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m---------------\u001b[0m \u001b[1m\u001b[94mfields in this struct\u001b[0m\n\u001b[1m\u001b[94m453\u001b[0m \u001b[1m\u001b[94m|\u001b[0m api_key: String,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^\u001b[0m\n\u001b[1m\u001b[94m454\u001b[0m \u001b[1m\u001b[94m|\u001b[0m base_url: String,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^\u001b[0m\n\u001b[1m\u001b[94m455\u001b[0m \u001b[1m\u001b[94m|\u001b[0m models: Vec,\n\u001b[1m\u001b[94m456\u001b[0m \u001b[1m\u001b[94m|\u001b[0m client: reqwest::Client,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m\n \u001b[1m\u001b[94m= \u001b[0m\u001b[1mnote\u001b[0m: `AnthropicClient` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: field `routing_table` is never read\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/ai/inference.rs:719:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m716\u001b[0m \u001b[1m\u001b[94m|\u001b[0m pub struct ModelRouter {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m-----------\u001b[0m \u001b[1m\u001b[94mfield in this struct\u001b[0m\n\u001b[1m\u001b[94m...\u001b[0m\n\u001b[1m\u001b[94m719\u001b[0m \u001b[1m\u001b[94m|\u001b[0m routing_table: RwLock>,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m\n \u001b[1m\u001b[94m= \u001b[0m\u001b[1mnote\u001b[0m: `ModelRouter` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: field `cost_history` is never read\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/ai/inference.rs:951:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m947\u001b[0m \u001b[1m\u001b[94m|\u001b[0m pub struct TokenCounter {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m------------\u001b[0m \u001b[1m\u001b[94mfield in this struct\u001b[0m\n\u001b[1m\u001b[94m...\u001b[0m\n\u001b[1m\u001b[94m951\u001b[0m \u001b[1m\u001b[94m|\u001b[0m cost_history: RwLock>,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: constant `HEALTH_CHECK_TIMEOUT_MS` is never used\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/bridge.rs:64:7\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m64\u001b[0m \u001b[1m\u001b[94m|\u001b[0m const HEALTH_CHECK_TIMEOUT_MS: u64 = 1000;\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: field `id` is never read\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/bridge.rs:152:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m151\u001b[0m \u001b[1m\u001b[94m|\u001b[0m struct PoolEntry {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m---------\u001b[0m \u001b[1m\u001b[94mfield in this struct\u001b[0m\n\u001b[1m\u001b[94m152\u001b[0m \u001b[1m\u001b[94m|\u001b[0m id: usize,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: method `stats` is never used\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/bridge.rs:195:8\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m163\u001b[0m \u001b[1m\u001b[94m|\u001b[0m impl ConnectionPool {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m-------------------\u001b[0m \u001b[1m\u001b[94mmethod in this implementation\u001b[0m\n\u001b[1m\u001b[94m...\u001b[0m\n\u001b[1m\u001b[94m195\u001b[0m \u001b[1m\u001b[94m|\u001b[0m fn stats(&self) -> PoolStats {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: struct `PoolStats` is never constructed\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/bridge.rs:203:8\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m203\u001b[0m \u001b[1m\u001b[94m|\u001b[0m struct PoolStats {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: fields `circuit_breaker_trips` and `health_check_failures` are never read\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/connector/bridge.rs:229:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m225\u001b[0m \u001b[1m\u001b[94m|\u001b[0m struct BridgeStats {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m-----------\u001b[0m \u001b[1m\u001b[94mfields in this struct\u001b[0m\n\u001b[1m\u001b[94m...\u001b[0m\n\u001b[1m\u001b[94m229\u001b[0m \u001b[1m\u001b[94m|\u001b[0m circuit_breaker_trips: u64,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n\u001b[1m\u001b[94m230\u001b[0m \u001b[1m\u001b[94m|\u001b[0m health_check_failures: u64,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^^^^^^^^^\u001b[0m\n \u001b[1m\u001b[94m|\u001b[0m\n \u001b[1m\u001b[94m= \u001b[0m\u001b[1mnote\u001b[0m: `BridgeStats` has derived impls for the traits `Clone` and `Debug`, but these are intentionally ignored during dead code analysis\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: field `consumers` is never read\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/messaging/mod.rs:38:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m35\u001b[0m \u001b[1m\u001b[94m|\u001b[0m pub struct MessageBroker {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m-------------\u001b[0m \u001b[1m\u001b[94mfield in this struct\u001b[0m\n\u001b[1m\u001b[94m...\u001b[0m\n\u001b[1m\u001b[94m38\u001b[0m \u001b[1m\u001b[94m|\u001b[0m consumers: DashMap>>,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: field `version` is never read\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/protocol/messages.rs:293:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m291\u001b[0m \u001b[1m\u001b[94m|\u001b[0m pub struct MessageRegistry {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m---------------\u001b[0m \u001b[1m\u001b[94mfield in this struct\u001b[0m\n\u001b[1m\u001b[94m292\u001b[0m \u001b[1m\u001b[94m|\u001b[0m handlers: HashMap,\n\u001b[1m\u001b[94m293\u001b[0m \u001b[1m\u001b[94m|\u001b[0m version: u32,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: field `version` is never read\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/protocol/serialize.rs:258:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m255\u001b[0m \u001b[1m\u001b[94m|\u001b[0m struct Schema {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m------\u001b[0m \u001b[1m\u001b[94mfield in this struct\u001b[0m\n\u001b[1m\u001b[94m...\u001b[0m\n\u001b[1m\u001b[94m258\u001b[0m \u001b[1m\u001b[94m|\u001b[0m version: u32,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: fields `required` and `default_value` are never read\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/protocol/serialize.rs:264:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m261\u001b[0m \u001b[1m\u001b[94m|\u001b[0m struct SchemaField {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m-----------\u001b[0m \u001b[1m\u001b[94mfields in this struct\u001b[0m\n\u001b[1m\u001b[94m...\u001b[0m\n\u001b[1m\u001b[94m264\u001b[0m \u001b[1m\u001b[94m|\u001b[0m required: bool,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^\u001b[0m\n\u001b[1m\u001b[94m265\u001b[0m \u001b[1m\u001b[94m|\u001b[0m default_value: Option,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: variant `Custom` is never constructed\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/protocol/serialize.rs:276:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m269\u001b[0m \u001b[1m\u001b[94m|\u001b[0m enum FieldValidation {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m---------------\u001b[0m \u001b[1m\u001b[94mvariant in this enum\u001b[0m\n\u001b[1m\u001b[94m...\u001b[0m\n\u001b[1m\u001b[94m276\u001b[0m \u001b[1m\u001b[94m|\u001b[0m Custom(String),\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: fields `next_request_id`, `pending_requests`, `serializer`, and `timeout_ms` are never read\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/protocol/rpc.rs:218:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m217\u001b[0m \u001b[1m\u001b[94m|\u001b[0m pub struct RpcClient {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m---------\u001b[0m \u001b[1m\u001b[94mfields in this struct\u001b[0m\n\u001b[1m\u001b[94m218\u001b[0m \u001b[1m\u001b[94m|\u001b[0m next_request_id: AtomicU64,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^^^\u001b[0m\n\u001b[1m\u001b[94m219\u001b[0m \u001b[1m\u001b[94m|\u001b[0m pending_requests: Arc, RpcError>>>>>,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^^^^^^^\u001b[0m\n\u001b[1m\u001b[94m220\u001b[0m \u001b[1m\u001b[94m|\u001b[0m serializer: Serializer,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^\u001b[0m\n\u001b[1m\u001b[94m221\u001b[0m \u001b[1m\u001b[94m|\u001b[0m timeout_ms: u64,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: field `serializer` is never read\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/protocol/rpc.rs:271:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m269\u001b[0m \u001b[1m\u001b[94m|\u001b[0m pub struct RpcServer {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m---------\u001b[0m \u001b[1m\u001b[94mfield in this struct\u001b[0m\n\u001b[1m\u001b[94m270\u001b[0m \u001b[1m\u001b[94m|\u001b[0m handlers: HashMap,\n\u001b[1m\u001b[94m271\u001b[0m \u001b[1m\u001b[94m|\u001b[0m serializer: Serializer,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m\u001b[1m: field `events` is never read\u001b[0m\n \u001b[1m\u001b[94m--> \u001b[0msrc/registry/mod.rs:31:5\n \u001b[1m\u001b[94m|\u001b[0m\n\u001b[1m\u001b[94m28\u001b[0m \u001b[1m\u001b[94m|\u001b[0m pub struct ServiceRegistry {\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[94m---------------\u001b[0m \u001b[1m\u001b[94mfield in this struct\u001b[0m\n\u001b[1m\u001b[94m...\u001b[0m\n\u001b[1m\u001b[94m31\u001b[0m \u001b[1m\u001b[94m|\u001b[0m events: Arc>>,\n \u001b[1m\u001b[94m|\u001b[0m \u001b[1m\u001b[33m^^^^^^\u001b[0m\n\n\u001b[1m\u001b[33mwarning\u001b[0m: `tent-backend` (lib) generated 52 warnings (run `cargo fix --lib -p tent-backend` to apply 23 suggestions)\n\u001b[1m\u001b[92m Finished\u001b[0m `dev` profile [unoptimized + debuginfo] target(s) in 2m 14s" + }, + { + "name": "frontend", + "status": "PASS", + "elapsed_seconds": 29.334, + "artifact": "frontend/dist", + "output": "> tent-frontend@0.0.0 build\n> tsc -b && vite build\n\nvite v6.4.3 building for production...\ntransforming...\n\u2713 100 modules transformed.\nrendering chunks...\ncomputing gzip size...\ndist/index.html 0.63 kB \u2502 gzip: 0.35 kB\ndist/assets/state-BkjSKDbY.js 8.91 kB \u2502 gzip: 3.54 kB \u2502 map: 57.15 kB\ndist/assets/vendor-CREcWLHI.js 48.93 kB \u2502 gzip: 17.25 kB \u2502 map: 481.27 kB\ndist/assets/index-CyxcoTyU.js 231.32 kB \u2502 gzip: 72.16 kB \u2502 map: 1,045.57 kB\n\u2713 built in 5.86s\nnpm notice\nnpm notice New major version of npm available! 10.9.4 -> 11.17.0\nnpm notice Changelog: https://github.com/npm/cli/releases/tag/v11.17.0\nnpm notice To update run: npm install -g npm@11.17.0\nnpm notice" + }, + { + "name": "market", + "status": "PASS", + "elapsed_seconds": 7.504, + "artifact": "market/market", + "output": "go: downloading go.uber.org/zap v1.27.0\ngo: downloading github.com/shopspring/decimal v1.4.0\ngo: downloading github.com/google/uuid v1.6.0\ngo: downloading github.com/gorilla/websocket v1.5.3\ngo: downloading go.uber.org/multierr v1.10.0" + }, + { + "name": "frailbox", + "status": "FAIL", + "elapsed_seconds": 0.509, + "artifact": null, + "output": "gcc -Wall -Wextra -Wpedantic -std=c2x -O2 -g -D_FORTIFY_SOURCE=3 -fstack-protector-strong -fPIE -Iinclude -MMD -MP -c src/arena.c -o build/src/arena.o\nsrc/arena.c: In function 'region_alloc':\nsrc/arena.c:13:36: error: 'MAP_ANONYMOUS' undeclared (first use in this function)\n 13 | int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;\n | ^~~~~~~~~~~~~\nsrc/arena.c:13:36: note: each undeclared identifier is reported only once for each function it appears in\nsrc/arena.c:17:23: error: 'MAP_HUGETLB' undeclared (first use in this function)\n 17 | mmap_flags |= MAP_HUGETLB;\n | ^~~~~~~~~~~\nsrc/arena.c: In function 'arena_contains':\nsrc/arena.c:179:17: warning: comparison of distinct pointer types lacks a cast\n 179 | ptr < (char *)region->start + region->size) {\n | ^\nmake: *** [Makefile:27: build/src/arena.o] Error 1" + }, + { + "name": "engine", + "status": "FAIL", + "elapsed_seconds": 5.289, + "artifact": null, + "output": "[ 11%] Building CXX object CMakeFiles/trial-engine.dir/main.cpp.o\n/frailbox/engine/main.cpp:12:10: fatal error: format: No such file or directory\n 12 | #include \n | ^~~~~~~~\ncompilation terminated.\ngmake[2]: *** [CMakeFiles/trial-engine.dir/build.make:76: CMakeFiles/trial-engine.dir/main.cpp.o] Error 1\ngmake[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/trial-engine.dir/all] Error 2\ngmake: *** [Makefile:136: all] Error 2" + }, + { + "name": "compliance", + "status": "PASS", + "elapsed_seconds": 2.001, + "artifact": "compliance/build", + "output": "" + }, + { + "name": "v2-market-stream", + "status": "PASS", + "elapsed_seconds": 0.028, + "artifact": null, + "output": "Syntax OK\nruby: warning: shebang line ending with \\r may cause problems" + }, + { + "name": "nfc-scanner", + "status": "PASS", + "elapsed_seconds": 0.006, + "artifact": null, + "output": "" + }, + { + "name": "openapi-haskell", + "status": "FAIL", + "elapsed_seconds": 0, + "artifact": null, + "output": "Command not found: [Errno 2] No such file or directory: 'ghc'" + }, + { + "name": "openapi-tools", + "status": "PASS", + "elapsed_seconds": 0.018, + "artifact": null, + "output": "" + } + ], + "pr_note": "Include the encrypted diagnostic logd artifact(s): diagnostic/build-0c8d9252.logd. The encrypted .logd is the required diagnostic content for PR review; this JSON file is metadata. Maintainers may ask you to remove these diagnostic artifacts before merging." +} diff --git a/diagnostic/build-0c8d9252.logd b/diagnostic/build-0c8d9252.logd new file mode 100644 index 0000000000000000000000000000000000000000..d51fccdf4282e8c4290c49e79c4022839692bf5d GIT binary patch literal 39060 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