Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license

This commit is contained in:
2026-09-05 13:26:46 +03:00
commit 03634b1ca3
11340 changed files with 3442369 additions and 0 deletions
+38
View File
@@ -0,0 +1,38 @@
"""Project verification subsystem.
Ported from superagent-ai/grok-cli's verify subsystem (scoped):
static run-recipe detection, a persisted environment manifest, and a
smoke-test runner used by the ``hermes verify`` CLI command.
Sources:
- https://github.com/superagent-ai/grok-cli/blob/main/src/verify/recipes.ts
- https://github.com/superagent-ai/grok-cli/blob/main/src/verify/environment.ts
"""
from agent.verify.environment import (
load_manifest,
load_or_detect,
manifest_path,
save_manifest,
)
from agent.verify.recipes import Recipe, detect_package_manager, detect_recipe
from agent.verify.runner import (
PhaseResult,
ReadinessResult,
VerifyResult,
run_verify,
)
__all__ = [
"Recipe",
"detect_recipe",
"detect_package_manager",
"load_manifest",
"save_manifest",
"load_or_detect",
"manifest_path",
"run_verify",
"PhaseResult",
"ReadinessResult",
"VerifyResult",
]
+75
View File
@@ -0,0 +1,75 @@
"""Environment manifest for project verification.
Ported from superagent-ai/grok-cli ``src/verify/environment.ts``.
The manifest lives at ``<project>/.hermes/environment.json`` and is the
user-editable source of truth: when present and valid it wins over fresh
static detection.
"""
from __future__ import annotations
import json
from datetime import datetime, timezone
from pathlib import Path
from agent.verify.recipes import Recipe, detect_recipe
MANIFEST_VERSION = 1
_MANIFEST_RELPATH = Path(".hermes") / "environment.json"
def manifest_path(root: Path) -> Path:
"""Path of the verify manifest for the project at ``root``."""
return Path(root) / _MANIFEST_RELPATH
def load_manifest(root: Path) -> Recipe | None:
"""Load the saved recipe from the manifest, tolerating malformed files.
Mirrors grok's ``loadVerifyEnvironment``: any read/parse/shape problem
returns ``None`` rather than raising, so a corrupt manifest degrades to
fresh detection instead of breaking ``hermes verify``.
"""
path = manifest_path(root)
try:
raw = path.read_text(encoding="utf-8")
except OSError:
return None
try:
manifest = json.loads(raw)
except (json.JSONDecodeError, ValueError):
return None
if not isinstance(manifest, dict):
return None
# Accept both the wrapped {version, recipe} shape and a bare recipe.
recipe_raw = manifest.get("recipe", manifest)
return Recipe.from_dict(recipe_raw)
def save_manifest(root: Path, recipe: Recipe) -> Path:
"""Persist ``recipe`` as the project's verify manifest.
Writes the versioned wrapper shape (grok's ``saveVerifyEnvironment``
equivalent) and returns the manifest path.
"""
path = manifest_path(root)
path.parent.mkdir(parents=True, exist_ok=True)
payload = {
"version": MANIFEST_VERSION,
"recipe": recipe.to_dict(),
"updatedAt": datetime.now(timezone.utc).isoformat(),
}
path.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
return path
def load_or_detect(root: Path) -> tuple[Recipe | None, str]:
"""Return (recipe, source) where source is 'manifest' or 'detected'.
A saved manifest wins over fresh detection, matching grok-cli's
behavior where ``.grok/environment.json`` is the source of truth.
"""
saved = load_manifest(root)
if saved is not None:
return saved, "manifest"
return detect_recipe(root), "detected"
+477
View File
@@ -0,0 +1,477 @@
"""Static run-recipe detection for project verification.
Ported nearly 1:1 from superagent-ai/grok-cli ``src/verify/recipes.ts``.
Mirrors grok's detection order and command choices: Node (lockfile-based
package-manager choice + framework detection), Python (Django / FastAPI /
generic, with uv/poetry/pipenv awareness), Go, Rust, Java (Maven/Gradle),
Makefile fallback, plus a docker-compose recipe.
Layer ownership vs :mod:`agent.coding_context`:
- ``agent.coding_context.detect_project_facts`` owns the *cheap prompt-time
facts* — manifests, package managers, and test/lint/build verify commands
surfaced in the system-prompt workspace snapshot, the verify-on-stop nudge,
and the desktop verify UI. Its output must stay byte-stable and fast; do
not push runtime detection into it.
- This module owns the *deep runtime recipe* — framework identification,
bootstrap/build/test command inference, and crucially the start command,
port, and readiness path that let ``hermes verify`` boot the app and prove
it serves HTTP. The ``hermes verify`` CLI merges any project-facts verify
commands the recipe missed into its test list (see
``hermes_cli.verify_cmd._merge_project_facts_commands``) so the two layers
extend rather than contradict each other.
"""
from __future__ import annotations
import json
import re
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any
@dataclass
class Recipe:
"""A runnable verification recipe for a project.
Mirrors grok-cli's ``VerifyRecipe`` with a scoped field set:
``name`` is the human label (grok's ``appLabel``), ``kind`` the
detector id (grok's ``appKind``), and command lists are shell strings
executed in the project root.
"""
name: str
kind: str = "unknown"
bootstrap: list[str] = field(default_factory=list)
build: list[str] = field(default_factory=list)
test: list[str] = field(default_factory=list)
start: str | None = None
port: int | None = None
readiness_path: str = "/"
evidence: list[str] = field(default_factory=list)
def to_dict(self) -> dict[str, Any]:
return {
"name": self.name,
"kind": self.kind,
"bootstrap": list(self.bootstrap),
"build": list(self.build),
"test": list(self.test),
"start": self.start,
"port": self.port,
"readinessPath": self.readiness_path,
"evidence": list(self.evidence),
}
@classmethod
def from_dict(cls, raw: Any) -> "Recipe | None":
"""Tolerant loader mirroring grok's ``normalizeVerifyRecipe``."""
if not isinstance(raw, dict):
return None
name = raw.get("name") or raw.get("appLabel")
if not isinstance(name, str) or not name.strip():
return None
kind = raw.get("kind") or raw.get("appKind") or "unknown"
if not isinstance(kind, str) or not kind.strip():
kind = "unknown"
def as_strings(value: Any) -> list[str]:
if isinstance(value, str) and value.strip():
return [value.strip()]
if not isinstance(value, list):
return []
return [v.strip() for v in value if isinstance(v, str) and v.strip()]
start = raw.get("start") or raw.get("startCommand")
if not (isinstance(start, str) and start.strip()):
start = None
else:
start = start.strip()
port_raw = raw.get("port") or raw.get("startPort")
port: int | None = None
if isinstance(port_raw, int) and 0 < port_raw < 65536:
port = port_raw
elif isinstance(port_raw, str) and port_raw.strip().isdigit():
candidate = int(port_raw.strip())
if 0 < candidate < 65536:
port = candidate
readiness = raw.get("readinessPath") or raw.get("readiness_path") or "/"
if not (isinstance(readiness, str) and readiness.startswith("/")):
readiness = "/"
return cls(
name=name.strip(),
kind=kind.strip(),
bootstrap=as_strings(raw.get("bootstrap") or raw.get("installCommands")),
build=as_strings(raw.get("build") or raw.get("buildCommands")),
test=as_strings(raw.get("test") or raw.get("testCommands")),
start=start,
port=port,
readiness_path=readiness,
evidence=as_strings(raw.get("evidence")),
)
# ---------------------------------------------------------------------------
# helpers
# ---------------------------------------------------------------------------
def _read_text(root: Path, name: str) -> str | None:
try:
return (root / name).read_text(encoding="utf-8")
except OSError:
return None
def _read_package_json(root: Path) -> dict[str, Any] | None:
raw = _read_text(root, "package.json")
if raw is None:
return None
try:
parsed = json.loads(raw)
except (json.JSONDecodeError, ValueError):
return None
return parsed if isinstance(parsed, dict) else None
def detect_package_manager(root: Path) -> str | None:
"""Lockfile-based package-manager detection (grok's detectPackageManager)."""
candidates = [
("pnpm-lock.yaml", "pnpm"),
("bun.lock", "bun"),
("bun.lockb", "bun"),
("yarn.lock", "yarn"),
("package-lock.json", "npm"),
("uv.lock", "uv"),
("poetry.lock", "poetry"),
("Pipfile.lock", "pipenv"),
]
for filename, manager in candidates:
if (root / filename).exists():
return manager
return None
def _infer_port_from_command(command: str | None) -> int | None:
"""Port inference from a start command (grok's inferPortFromCommand)."""
if not command:
return None
flag = re.search(r"(?:--port|-p)\s+(\d{2,5})", command)
if flag:
return int(flag.group(1))
env = re.search(r"\bPORT=(\d{2,5})\b", command)
if env:
return int(env.group(1))
return None
def _dedupe(values: list[str | None]) -> list[str]:
seen: dict[str, None] = {}
for value in values:
if value and value.strip():
seen.setdefault(value.strip(), None)
return list(seen)
# ---------------------------------------------------------------------------
# Node
# ---------------------------------------------------------------------------
def _script_runner(package_manager: str | None, entry: str) -> str:
if package_manager == "pnpm":
return f"pnpm {entry}"
if package_manager == "bun":
return f"bun run {entry}"
if package_manager == "yarn":
return f"yarn {entry}"
return f"npm run {entry}"
def _detect_node_recipe(root: Path, pkg: dict[str, Any]) -> Recipe:
raw_scripts = pkg.get("scripts")
scripts: dict[str, str] = raw_scripts if isinstance(raw_scripts, dict) else {}
deps: dict[str, Any] = {}
for key in ("dependencies", "devDependencies"):
section = pkg.get(key)
if isinstance(section, dict):
deps.update(section)
package_manager = detect_package_manager(root)
kind, label, default_port = "node", "Node.js app", None
if "next" in deps:
kind, label, default_port = "nextjs", "Next.js", 3000
elif "@sveltejs/kit" in deps:
kind, label, default_port = "sveltekit", "SvelteKit", 5173
elif "astro" in deps:
kind, label, default_port = "astro", "Astro", 4321
elif "@remix-run/dev" in deps or "@remix-run/react" in deps:
kind, label, default_port = "remix", "Remix", 3000
elif "react-scripts" in deps:
kind, label, default_port = "cra", "Create React App", 3000
elif "vite" in deps:
kind, label, default_port = "vite", "Vite", 5173
install = {
"pnpm": "pnpm install",
"bun": "bun install",
"yarn": "yarn install",
"npm": "npm install",
}.get(package_manager or "npm", "npm install")
start_script = "dev" if scripts.get("dev") else ("start" if scripts.get("start") else None)
start_body = scripts.get(start_script) if start_script else None
start = _script_runner(package_manager, start_script) if start_script else None
port = _infer_port_from_command(start_body) or default_port if start else None
build = _dedupe(
[_script_runner(package_manager, s) for s in ("build", "typecheck") if scripts.get(s)]
)
test = _dedupe(
[_script_runner(package_manager, s) for s in ("test", "check", "lint") if scripts.get(s)]
)
return Recipe(
name=label,
kind=kind,
bootstrap=[install],
build=build,
test=test,
start=start,
port=port,
evidence=_dedupe(
[
"Detected package.json",
f"Package manager: {package_manager}" if package_manager else None,
f"Scripts: {', '.join(scripts) or '(none)'}",
]
),
)
# ---------------------------------------------------------------------------
# Python
# ---------------------------------------------------------------------------
def _detect_python_recipe(root: Path) -> Recipe | None:
pyproject = _read_text(root, "pyproject.toml")
requirements = _read_text(root, "requirements.txt")
manage_py = (root / "manage.py").exists()
if not (pyproject or requirements or manage_py or (root / "setup.py").exists()):
return None
lower = f"{pyproject or ''}\n{requirements or ''}".lower()
package_manager = detect_package_manager(root)
is_django = manage_py or "django" in lower
is_fastapi = "fastapi" in lower or "uvicorn" in lower
is_flask = "flask" in lower
install = "pip install -r requirements.txt"
if package_manager == "uv":
install = "uv sync"
elif package_manager == "poetry":
install = "poetry install"
elif package_manager == "pipenv":
install = "pipenv install"
elif pyproject and not requirements:
install = "pip install -e ."
has_tests = (root / "tests").exists()
if is_django:
return Recipe(
name="Django app",
kind="django",
bootstrap=[install],
test=["python manage.py test"],
start="python manage.py runserver 0.0.0.0:8000",
port=8000,
evidence=_dedupe(
[
"Detected manage.py" if manage_py else "Detected Django dependency",
"Detected pyproject.toml" if pyproject else None,
]
),
)
if is_fastapi:
if (root / "main.py").exists():
app_module = "main:app"
elif (root / "app.py").exists():
app_module = "app:app"
else:
app_module = "main:app"
return Recipe(
name="FastAPI app",
kind="fastapi",
bootstrap=[install],
test=["pytest"] if has_tests else [],
start=f"uvicorn {app_module} --host 0.0.0.0 --port 8000",
port=8000,
evidence=["Detected Python project", "Detected FastAPI/Uvicorn dependency"],
)
if is_flask:
if (root / "app.py").exists():
app_module = "app.py"
elif (root / "main.py").exists():
app_module = "main.py"
else:
app_module = "app.py"
return Recipe(
name="Flask app",
kind="flask",
bootstrap=[install],
test=["pytest"] if has_tests else [],
start=f"flask --app {app_module} run --host 0.0.0.0 --port 5000",
port=5000,
evidence=["Detected Python project", "Detected Flask dependency"],
)
return Recipe(
name="Python project",
kind="python",
bootstrap=[install],
test=["pytest"] if has_tests else ["python -m unittest discover"],
evidence=["Detected Python project"],
)
# ---------------------------------------------------------------------------
# Go / Rust / Java / Make / docker-compose
# ---------------------------------------------------------------------------
def _detect_go_recipe(root: Path) -> Recipe | None:
if not (root / "go.mod").exists():
return None
return Recipe(
name="Go project",
kind="go",
build=["go build ./..."],
test=["go test ./..."],
start="go run ." if (root / "main.go").exists() else None,
evidence=["Detected go.mod"],
)
def _detect_rust_recipe(root: Path) -> Recipe | None:
if not (root / "Cargo.toml").exists():
return None
return Recipe(
name="Rust project",
kind="rust",
build=["cargo build"],
test=["cargo test"],
start="cargo run" if (root / "src" / "main.rs").exists() else None,
evidence=["Detected Cargo.toml"],
)
def _detect_java_recipe(root: Path) -> Recipe | None:
if (root / "pom.xml").exists():
return Recipe(
name="Maven project",
kind="maven",
build=["mvn package"],
test=["mvn test"],
evidence=["Detected pom.xml"],
)
if (root / "build.gradle").exists() or (root / "build.gradle.kts").exists():
gradle = "./gradlew" if (root / "gradlew").exists() else "gradle"
return Recipe(
name="Gradle project",
kind="gradle",
build=[f"{gradle} build"],
test=[f"{gradle} test"],
evidence=["Detected Gradle build file"],
)
return None
_MAKE_TARGET_RE = re.compile(r"^([A-Za-z0-9_.-]+):(?:\s|$)")
def _parse_make_targets(raw: str) -> list[str]:
targets = []
for line in raw.splitlines():
match = _MAKE_TARGET_RE.match(line)
if match:
targets.append(match.group(1))
return targets
def _detect_make_recipe(root: Path) -> Recipe | None:
makefile = _read_text(root, "Makefile")
if makefile is None:
return None
targets = _parse_make_targets(makefile)
def pick(names: list[str]) -> str | None:
for name in names:
if name in targets:
return name
return None
install = pick(["install", "setup", "bootstrap"])
build = pick(["build", "compile"])
test = pick(["test", "check"])
run = pick(["run", "start", "serve", "dev"])
return Recipe(
name="Makefile-driven project",
kind="make",
bootstrap=[f"make {install}"] if install else [],
build=[f"make {build}"] if build else [],
test=[f"make {test}"] if test else [],
start=f"make {run}" if run else None,
evidence=["Detected Makefile", f"Targets: {', '.join(targets) or '(none)'}"],
)
_COMPOSE_FILES = (
"docker-compose.yml",
"docker-compose.yaml",
"compose.yml",
"compose.yaml",
)
def _detect_compose_recipe(root: Path) -> Recipe | None:
compose_file = next((f for f in _COMPOSE_FILES if (root / f).exists()), None)
if compose_file is None:
return None
return Recipe(
name="docker-compose project",
kind="compose",
build=["docker compose build"],
start="docker compose up",
evidence=[f"Detected {compose_file}"],
)
# ---------------------------------------------------------------------------
# entry point
# ---------------------------------------------------------------------------
def detect_recipe(root: Path) -> Recipe | None:
"""Detect a verification recipe for the project at ``root``.
Detection order mirrors grok-cli's ``inferFallbackRecipe``: package.json
wins, then Python, Go, Rust, Java, then Makefile / docker-compose
fallbacks. Returns ``None`` when nothing recognizable is found.
"""
root = Path(root)
pkg = _read_package_json(root)
if pkg is not None:
return _detect_node_recipe(root, pkg)
return (
_detect_python_recipe(root)
or _detect_go_recipe(root)
or _detect_rust_recipe(root)
or _detect_java_recipe(root)
or _detect_make_recipe(root)
or _detect_compose_recipe(root)
)
+279
View File
@@ -0,0 +1,279 @@
"""Verification runner: execute a Recipe's phases and smoke-test the app.
Scoped port of the execution flow grok-cli's verify sub-agent performs
(install/bootstrap -> build -> test -> start in background -> curl-style
readiness loop -> teardown), reimplemented as a plain subprocess runner.
Commands come from the project's own recipe (its package.json scripts,
Makefile targets, etc.) and are executed with ``shell=True`` on purpose:
this is a developer tool running the project's own build commands in the
project's own checkout — the same trust level as the terminal tool.
"""
from __future__ import annotations
import os
import signal
import subprocess
import time
import urllib.error
import urllib.request
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Callable
from agent.verify.recipes import Recipe
DEFAULT_PHASE_TIMEOUT = 600.0
DEFAULT_READY_TIMEOUT = 60.0
_TAIL_CHARS = 2000
PHASE_ORDER = ("bootstrap", "build", "test")
@dataclass
class PhaseResult:
phase: str
command: str
exit_code: int | None
duration: float
output_tail: str
timed_out: bool = False
@property
def ok(self) -> bool:
return self.exit_code == 0 and not self.timed_out
def to_dict(self) -> dict[str, Any]:
return {
"phase": self.phase,
"command": self.command,
"exitCode": self.exit_code,
"duration": round(self.duration, 3),
"ok": self.ok,
"timedOut": self.timed_out,
"outputTail": self.output_tail,
}
@dataclass
class ReadinessResult:
url: str
ready: bool
status_code: int | None
duration: float
error: str | None = None
output_tail: str = ""
def to_dict(self) -> dict[str, Any]:
return {
"url": self.url,
"ready": self.ready,
"statusCode": self.status_code,
"duration": round(self.duration, 3),
"error": self.error,
"outputTail": self.output_tail,
}
@dataclass
class VerifyResult:
recipe_name: str
phases: list[PhaseResult] = field(default_factory=list)
readiness: ReadinessResult | None = None
@property
def ok(self) -> bool:
phases_ok = all(p.ok for p in self.phases)
readiness_ok = self.readiness.ready if self.readiness is not None else True
return phases_ok and readiness_ok
def to_dict(self) -> dict[str, Any]:
return {
"recipe": self.recipe_name,
"ok": self.ok,
"phases": [p.to_dict() for p in self.phases],
"readiness": self.readiness.to_dict() if self.readiness else None,
}
def _tail(text: str, limit: int = _TAIL_CHARS) -> str:
return text[-limit:] if len(text) > limit else text
def _run_phase_command(
phase: str,
command: str,
root: Path,
timeout: float,
on_output: Callable[[str], None] | None = None,
) -> PhaseResult:
started = time.monotonic()
try:
proc = subprocess.run(
command,
shell=True, # project-authored commands; see module docstring
cwd=str(root),
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
timeout=timeout,
text=True,
errors="replace",
)
output = proc.stdout or ""
exit_code: int | None = proc.returncode
timed_out = False
except subprocess.TimeoutExpired as exc:
raw = exc.output
if isinstance(raw, bytes):
output = raw.decode("utf-8", errors="replace")
else:
output = raw or ""
exit_code = None
timed_out = True
duration = time.monotonic() - started
if on_output and output:
on_output(output)
return PhaseResult(
phase=phase,
command=command,
exit_code=exit_code,
duration=duration,
output_tail=_tail(output),
timed_out=timed_out,
)
def _poll_readiness(url: str, timeout: float, interval: float = 1.0) -> tuple[bool, int | None, str | None]:
deadline = time.monotonic() + timeout
last_error: str | None = None
while time.monotonic() < deadline:
try:
with urllib.request.urlopen(url, timeout=5) as resp:
return True, resp.status, None
except urllib.error.HTTPError as exc:
# The server answered — it is up, even if it returned 4xx/5xx.
return True, exc.code, None
except (urllib.error.URLError, OSError, TimeoutError) as exc:
last_error = str(exc)
time.sleep(interval)
return False, None, last_error
def _terminate_process_group(proc: subprocess.Popen) -> None:
"""Terminate the started app and its whole process group cleanly.
On POSIX the child is spawned with ``start_new_session=True`` so we can
signal the whole group; on Windows (no ``os.killpg``) we fall back to
terminating just the direct child.
"""
if proc.poll() is not None:
return
killpg = getattr(os, "killpg", None)
getpgid = getattr(os, "getpgid", None)
pgid = None
if killpg is not None and getpgid is not None:
try:
pgid = getpgid(proc.pid)
except (ProcessLookupError, PermissionError):
pgid = None
try:
if pgid is not None and killpg is not None:
killpg(pgid, signal.SIGTERM) # windows-footgun: ok — POSIX-only branch (killpg checked above)
else:
proc.terminate()
except (ProcessLookupError, PermissionError):
return
try:
proc.wait(timeout=10)
except subprocess.TimeoutExpired:
try:
if pgid is not None and killpg is not None:
killpg(pgid, signal.SIGKILL) # windows-footgun: ok — POSIX-only branch (killpg checked above)
else:
proc.kill()
except (ProcessLookupError, PermissionError):
pass
try:
proc.wait(timeout=5)
except subprocess.TimeoutExpired:
pass
def _run_start_phase(
recipe: Recipe,
root: Path,
ready_timeout: float,
port_override: int | None = None,
) -> ReadinessResult:
assert recipe.start is not None
port = port_override or recipe.port or 8000
url = f"http://127.0.0.1:{port}{recipe.readiness_path}"
started = time.monotonic()
proc = subprocess.Popen(
recipe.start,
shell=True, # project-authored command; see module docstring
cwd=str(root),
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
start_new_session=True, # own process group for clean teardown
text=True,
errors="replace",
)
output = ""
try:
ready, status, error = _poll_readiness(url, ready_timeout)
finally:
_terminate_process_group(proc)
try:
if proc.stdout is not None:
output = proc.stdout.read() or ""
except (OSError, ValueError):
output = ""
return ReadinessResult(
url=url,
ready=ready,
status_code=status,
duration=time.monotonic() - started,
error=error,
output_tail=_tail(output),
)
def run_verify(
root: Path,
recipe: Recipe,
phases: tuple[str, ...] | list[str] | None = None,
phase_timeout: float = DEFAULT_PHASE_TIMEOUT,
ready_timeout: float = DEFAULT_READY_TIMEOUT,
skip_start: bool = False,
port_override: int | None = None,
stop_on_failure: bool = True,
on_output: Callable[[str], None] | None = None,
) -> VerifyResult:
"""Run a verify pass for ``recipe`` at project ``root``.
Executes the selected command phases sequentially, then (unless
``skip_start`` or a phase failed) launches ``recipe.start`` in the
background, polls the readiness URL, and tears the process group down.
"""
root = Path(root)
selected = tuple(phases) if phases else PHASE_ORDER + ("start",)
result = VerifyResult(recipe_name=recipe.name)
failed = False
for phase in PHASE_ORDER:
if phase not in selected:
continue
for command in getattr(recipe, phase):
phase_result = _run_phase_command(phase, command, root, phase_timeout, on_output)
result.phases.append(phase_result)
if not phase_result.ok:
failed = True
if stop_on_failure:
return result
if skip_start or "start" not in selected or failed or not recipe.start:
return result
result.readiness = _run_start_phase(recipe, root, ready_timeout, port_override)
return result