Wl6adams's picture
Organize private Nexum release into Lite, Universal, and Expanded profiles
9a70a84
Raw
History Blame Contribute Delete
66.5 kB
"""Evidence-bound reproduction, triage, disclosure, and patch workflows."""
from __future__ import annotations
import hashlib
import hmac
import json
import os
import platform
import re
import secrets
import sys
import time
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Any, Callable, Mapping, Sequence
from .artifacts import ArtifactStore
from .contracts import (
ToolCall,
ToolExecutionContext,
ToolExecutionResult,
ToolParameter,
ToolSpec,
)
from .repository import atomic_patch_text, atomic_write_text
from .sandbox import control_root, ensure_control_root
from .security import SecretRedactor
from .transactions import TransactionStore
RunCommand = Callable[
[str, str, float], tuple[bool, str, str, int | None]
]
_ID_RE = re.compile(r"(?:rep|tri|dis|patch|evb)_[a-f0-9]{32}")
_SHA256_RE = re.compile(r"[a-f0-9]{64}")
_SEVERITIES = ("informational", "low", "moderate", "high", "critical")
_AUDIENCES = ("maintainer", "operator", "coordinated", "public")
ENGINEERING_TOOL_SPECS: tuple[ToolSpec, ...] = (
ToolSpec(
"ReproductionRun",
"engineering",
"Run one contained reproduction attempt and persist exact environment, state, output, and exit evidence.",
"ReproductionRun(command='python -m pytest tests/test_api.py', snapshot_paths=['src', 'tests'])",
(
ToolParameter("command", "string", "Exact contained command to execute."),
ToolParameter(
"working_directory",
"string",
"Optional workspace-relative working directory.",
required=False,
),
ToolParameter(
"snapshot_paths",
"array",
"Optional workspace paths whose content state is captured before and after execution.",
required=False,
),
),
risk="workspace_write",
parallel_safe=False,
idempotent=False,
task_support="optional",
),
ToolSpec(
"ReproductionCompare",
"engineering",
"Compare any number of session reproduction receipts for stable outcomes and state drift.",
"ReproductionCompare(reproduction_ids=['rep_...', 'rep_...'])",
(
ToolParameter(
"reproduction_ids", "array", "Reproduction receipt identifiers."
),
),
),
ToolSpec(
"TriageCreate",
"engineering",
"Create evidence-linked triage that keeps observed facts separate from hypotheses and next actions.",
"TriageCreate(reproduction_ids=['rep_...'], observed_facts=['exit changed'], hypotheses=['configuration drift'], severity='moderate', confidence=0.7, next_actions=['inspect configuration'])",
(
ToolParameter(
"reproduction_ids", "array", "Cited reproduction receipt identifiers."
),
ToolParameter("observed_facts", "array", "Evidence-supported facts."),
ToolParameter("hypotheses", "array", "Unconfirmed explanations."),
ToolParameter(
"severity",
"string",
"Current impact classification.",
enum=_SEVERITIES,
),
ToolParameter("confidence", "number", "Confidence from zero to one."),
ToolParameter("next_actions", "array", "Model-selected investigation actions."),
),
risk="workspace_write",
parallel_safe=False,
idempotent=False,
),
ToolSpec(
"TriageStatus",
"engineering",
"Read one session-scoped triage receipt with its bound reproduction evidence and drift state.",
"TriageStatus(triage_id='tri_...')",
(ToolParameter("triage_id", "string", "Triage receipt identifier."),),
),
ToolSpec(
"TriageUpdate",
"engineering",
"Append new evidence, facts, hypotheses, and next actions to an existing triage receipt.",
"TriageUpdate(triage_id='tri_...', reproduction_ids=['rep_...'], observed_facts=['new fact'])",
(
ToolParameter("triage_id", "string", "Triage receipt identifier."),
ToolParameter(
"reproduction_ids",
"array",
"Additional reproduction receipt identifiers.",
required=False,
),
ToolParameter(
"observed_facts",
"array",
"Additional evidence-supported facts.",
required=False,
),
ToolParameter(
"hypotheses",
"array",
"Additional unconfirmed explanations.",
required=False,
),
ToolParameter(
"severity",
"string",
"Updated impact classification.",
required=False,
enum=_SEVERITIES,
),
ToolParameter(
"confidence",
"number",
"Updated confidence from zero to one.",
required=False,
),
ToolParameter(
"next_actions",
"array",
"Additional model-selected investigation actions.",
required=False,
),
),
risk="workspace_write",
parallel_safe=False,
idempotent=False,
),
ToolSpec(
"DisclosureCreate",
"engineering",
"Create a sanitized disclosure artifact from cited triage and optional verified patch evidence.",
"DisclosureCreate(triage_id='tri_...', title='Issue title', summary='Summary', impact='Impact', remediation='Resolution')",
(
ToolParameter("triage_id", "string", "Cited triage receipt identifier."),
ToolParameter("title", "string", "Disclosure title."),
ToolParameter("summary", "string", "Evidence-grounded summary."),
ToolParameter("impact", "string", "Observed or bounded impact."),
ToolParameter("remediation", "string", "Repair and verification guidance."),
ToolParameter(
"audience",
"string",
"Intended disclosure audience.",
required=False,
enum=_AUDIENCES,
),
ToolParameter(
"patch_id",
"string",
"Optional patch receipt to include by digest and verification state.",
required=False,
),
),
risk="workspace_write",
parallel_safe=False,
idempotent=False,
),
ToolSpec(
"DisclosureStatus",
"engineering",
"Read one session-scoped disclosure receipt and its sanitized artifact reference.",
"DisclosureStatus(disclosure_id='dis_...')",
(ToolParameter("disclosure_id", "string", "Disclosure receipt identifier."),),
),
ToolSpec(
"EvidenceBundleCreate",
"engineering",
"Create a sanitized handoff artifact from cited engineering receipts without raw private output.",
"EvidenceBundleCreate(title='Repair handoff', triage_ids=['tri_...'], patch_ids=['patch_...'])",
(
ToolParameter(
"title",
"string",
"Bundle title shown in the sanitized handoff artifact.",
),
ToolParameter(
"reproduction_ids",
"array",
"Optional reproduction receipt identifiers.",
required=False,
),
ToolParameter(
"triage_ids",
"array",
"Optional triage receipt identifiers.",
required=False,
),
ToolParameter(
"disclosure_ids",
"array",
"Optional disclosure receipt identifiers.",
required=False,
),
ToolParameter(
"patch_ids",
"array",
"Optional patch receipt identifiers.",
required=False,
),
),
risk="workspace_write",
parallel_safe=False,
idempotent=False,
),
ToolSpec(
"EvidenceBundleStatus",
"engineering",
"Read one session-scoped sanitized evidence bundle receipt.",
"EvidenceBundleStatus(bundle_id='evb_...')",
(ToolParameter("bundle_id", "string", "Evidence bundle receipt identifier."),),
),
ToolSpec(
"PatchBegin",
"engineering",
"Begin an evidence-linked multi-file patch transaction with immutable original snapshots.",
"PatchBegin(triage_id='tri_...', paths=['src/app.py', 'tests/test_app.py'])",
(
ToolParameter("triage_id", "string", "Cited triage receipt identifier."),
ToolParameter("paths", "array", "Exact workspace files covered by the patch."),
),
risk="workspace_write",
parallel_safe=False,
idempotent=False,
),
ToolSpec(
"PatchApply",
"engineering",
"Apply an atomic compare-and-swap patch set and restore every covered file if any change fails.",
"PatchApply(patch_id='patch_...', changes=[{'operation':'replace','path':'src/app.py','expected_sha256':'...','old_text':'before','new_text':'after'}])",
(
ToolParameter("patch_id", "string", "Patch receipt identifier."),
ToolParameter(
"changes",
"array",
"Changes using replace or write operations with exact current digests.",
),
),
risk="workspace_write",
parallel_safe=False,
idempotent=False,
),
ToolSpec(
"PatchVerify",
"engineering",
"Run contained model-selected verification and bind its reproduction receipt to the patch.",
"PatchVerify(patch_id='patch_...', command='python -m pytest tests/test_app.py')",
(
ToolParameter("patch_id", "string", "Patch receipt identifier."),
ToolParameter("command", "string", "Exact verification command."),
ToolParameter(
"working_directory",
"string",
"Optional workspace-relative working directory.",
required=False,
),
),
risk="workspace_write",
parallel_safe=False,
idempotent=False,
task_support="optional",
),
ToolSpec(
"PatchCommit",
"engineering",
"Commit only a successfully verified patch whose covered files still match the verified state.",
"PatchCommit(patch_id='patch_...')",
(ToolParameter("patch_id", "string", "Patch receipt identifier."),),
risk="workspace_write",
parallel_safe=False,
),
ToolSpec(
"PatchRollback",
"engineering",
"Restore the original patch snapshots only when every covered file still matches current receipts, then bind a restoration digest proof.",
"PatchRollback(patch_id='patch_...')",
(ToolParameter("patch_id", "string", "Patch receipt identifier."),),
risk="destructive",
parallel_safe=False,
idempotent=True,
),
ToolSpec(
"PatchStatus",
"engineering",
"Read patch mutations, verification receipts, transaction state, and rollback availability.",
"PatchStatus(patch_id='patch_...')",
(ToolParameter("patch_id", "string", "Patch receipt identifier."),),
),
)
ENGINEERING_TOOL_NAMES = frozenset(spec.name for spec in ENGINEERING_TOOL_SPECS)
_ENGINEERING_TOOL_BY_NAME = {spec.name: spec for spec in ENGINEERING_TOOL_SPECS}
@dataclass(frozen=True)
class FileState:
path: str
sha256: str
bytes: int
@dataclass(frozen=True)
class ReproductionRecord:
reproduction_id: str
session_sha256: str
command_sha256: str
working_directory: str
environment_sha256: str
before_state_sha256: str
after_state_sha256: str
before_files: tuple[FileState, ...]
after_files: tuple[FileState, ...]
stdout_artifact_id: str
stderr_artifact_id: str
stdout_sha256: str
stderr_sha256: str
exit_code: int | None
command_ok: bool
status: str
created_unix_ms: int
finished_unix_ms: int
def to_dict(self) -> dict[str, Any]:
return asdict(self)
@dataclass(frozen=True)
class TriageRecord:
triage_id: str
session_sha256: str
reproduction_ids: tuple[str, ...]
observed_facts: tuple[str, ...]
hypotheses: tuple[str, ...]
severity: str
confidence: float
next_actions: tuple[str, ...]
evidence_sha256: str
created_unix_ms: int
def to_dict(self) -> dict[str, Any]:
return asdict(self)
@dataclass(frozen=True)
class DisclosureRecord:
disclosure_id: str
session_sha256: str
triage_id: str
patch_id: str
audience: str
evidence_sha256: str
artifact_id: str
artifact_sha256: str
created_unix_ms: int
def to_dict(self) -> dict[str, Any]:
return asdict(self)
@dataclass(frozen=True)
class EvidenceBundleRecord:
bundle_id: str
session_sha256: str
title: str
reproduction_ids: tuple[str, ...]
triage_ids: tuple[str, ...]
disclosure_ids: tuple[str, ...]
patch_ids: tuple[str, ...]
evidence_sha256: str
artifact_id: str
artifact_sha256: str
created_unix_ms: int
def to_dict(self) -> dict[str, Any]:
return asdict(self)
@dataclass(frozen=True)
class PatchMutation:
operation: str
path: str
before_sha256: str
after_sha256: str
bytes: int
created: bool
@dataclass(frozen=True)
class PatchRecord:
patch_id: str
session_sha256: str
triage_id: str
transaction_id: str
paths: tuple[str, ...]
status: str
mutations: tuple[PatchMutation, ...]
verification_ids: tuple[str, ...]
verified_state_sha256: str
last_error: str
created_unix_ms: int
updated_unix_ms: int
restoration_sha256: str = ""
def to_dict(self) -> dict[str, Any]:
return asdict(self)
def _atomic_json(path: Path, payload: Mapping[str, Any]) -> None:
path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
os.chmod(path.parent, 0o700)
temporary = path.with_name(f".{path.name}.{secrets.token_hex(8)}.tmp")
temporary.write_text(
json.dumps(payload, sort_keys=True, separators=(",", ":")),
encoding="utf-8",
)
temporary.chmod(0o600)
with temporary.open("rb") as handle:
os.fsync(handle.fileno())
os.replace(temporary, path)
directory_fd = os.open(path.parent, os.O_RDONLY)
try:
os.fsync(directory_fd)
finally:
os.close(directory_fd)
def _session_sha256(session_id: str) -> str:
return hashlib.sha256((session_id or "direct").encode("utf-8")).hexdigest()
def _require_session(session_sha256: str, session_id: str) -> None:
if not hmac.compare_digest(session_sha256, _session_sha256(session_id)):
raise PermissionError("engineering receipt does not belong to this session")
def _record_path(root: Path, identifier: str, prefix: str) -> Path:
if not _ID_RE.fullmatch(identifier) or not identifier.startswith(prefix + "_"):
raise ValueError(f"{prefix} receipt id is invalid")
return root / f"{identifier}.json"
def _append_unique(existing: tuple[str, ...], additions: tuple[str, ...]) -> tuple[str, ...]:
rows = list(existing)
seen = set(rows)
for item in additions:
if item not in seen:
rows.append(item)
seen.add(item)
return tuple(rows)
def _load_payload(path: Path) -> dict[str, Any]:
payload = json.loads(path.read_text(encoding="utf-8"))
if not isinstance(payload, dict):
raise RuntimeError("engineering receipt is invalid")
return payload
def _string_tuple(value: object, name: str, *, allow_empty: bool = True) -> tuple[str, ...]:
if not isinstance(value, list) or any(not isinstance(item, str) for item in value):
raise ValueError(f"{name} must be an array of strings")
rendered = tuple(item.strip() for item in value)
if any(not item for item in rendered) or (not allow_empty and not rendered):
raise ValueError(f"{name} must contain non-empty strings")
return rendered
def _contained_path(
workspace: Path, raw_path: str, *, require_directory: bool = False
) -> Path:
raw = raw_path.strip() or "."
candidate = (workspace / raw).resolve()
try:
relative = candidate.relative_to(workspace)
except ValueError as exc:
raise ValueError("engineering path leaves the workspace") from exc
if relative.parts and relative.parts[0] == ".nexum":
raise ValueError("workspace control paths require dedicated runtime tools")
if require_directory and not candidate.is_dir():
raise ValueError("working directory does not exist")
return candidate
def _sha256_file(path: Path) -> tuple[str, int]:
digest = hashlib.sha256()
size = 0
with path.open("rb") as handle:
while chunk := handle.read(1024 * 1024):
digest.update(chunk)
size += len(chunk)
return digest.hexdigest(), size
def _snapshot(workspace: Path, raw_paths: tuple[str, ...]) -> tuple[FileState, ...]:
states: list[FileState] = []
seen: set[str] = set()
for raw_path in raw_paths:
target = _contained_path(workspace, raw_path)
if not target.exists():
relative = target.relative_to(workspace).as_posix()
if relative not in seen:
states.append(FileState(relative, "missing", 0))
seen.add(relative)
continue
candidates = (target,) if target.is_file() else tuple(sorted(target.rglob("*")))
for candidate in candidates:
if candidate.is_symlink():
raise ValueError("snapshot paths cannot contain symbolic links")
if not candidate.is_file():
continue
relative = candidate.resolve().relative_to(workspace).as_posix()
if relative.startswith(".nexum/") or relative.startswith(".git/"):
continue
if "/.git/" in f"/{relative}/" or relative in seen:
continue
digest, size = _sha256_file(candidate)
states.append(FileState(relative, digest, size))
seen.add(relative)
return tuple(sorted(states, key=lambda state: state.path))
def _state_sha256(states: tuple[FileState, ...]) -> str:
encoded = json.dumps(
[asdict(state) for state in states],
sort_keys=True,
separators=(",", ":"),
).encode("utf-8")
return hashlib.sha256(encoded).hexdigest()
def _sanitize(text: str, workspace: Path) -> str:
return SecretRedactor().redact(text).replace(str(workspace), "[WORKSPACE]")
class ReproductionStore:
def __init__(self, workspace: str | Path) -> None:
self.workspace = ensure_control_root(workspace)
self.root = control_root(self.workspace) / "engineering" / "reproductions"
self.root.mkdir(parents=True, exist_ok=True, mode=0o700)
os.chmod(self.root, 0o700)
self.artifacts = ArtifactStore(self.workspace)
def run(
self,
*,
command: str,
working_directory: str,
snapshot_paths: tuple[str, ...],
timeout_s: float,
session_id: str,
run_command: RunCommand,
) -> tuple[ReproductionRecord, str, str]:
if not command.strip():
raise ValueError("reproduction command is required")
workdir = _contained_path(
self.workspace, working_directory, require_directory=True
)
before = _snapshot(self.workspace, snapshot_paths)
relative_workdir = workdir.relative_to(self.workspace).as_posix() or "."
environment = {
"architecture": platform.machine(),
"os_name": platform.system(),
"os_release": platform.release(),
"python": ".".join(str(part) for part in sys.version_info[:3]),
"working_directory": relative_workdir,
}
environment_sha256 = hashlib.sha256(
json.dumps(environment, sort_keys=True, separators=(",", ":")).encode(
"utf-8"
)
).hexdigest()
started = int(time.time() * 1000)
command_ok, stdout, stderr, exit_code = run_command(
command, str(workdir), timeout_s
)
finished = int(time.time() * 1000)
safe_stdout = _sanitize(stdout, self.workspace)
safe_stderr = _sanitize(stderr, self.workspace)
after = _snapshot(self.workspace, snapshot_paths)
stdout_artifact = self.artifacts.put_text(
safe_stdout,
source="reproduction_stdout",
session_id=session_id or "direct",
)
stderr_artifact = self.artifacts.put_text(
safe_stderr,
source="reproduction_stderr",
session_id=session_id or "direct",
)
record = ReproductionRecord(
reproduction_id="rep_" + secrets.token_hex(16),
session_sha256=_session_sha256(session_id),
command_sha256=hashlib.sha256(command.encode("utf-8")).hexdigest(),
working_directory=relative_workdir,
environment_sha256=environment_sha256,
before_state_sha256=_state_sha256(before),
after_state_sha256=_state_sha256(after),
before_files=before,
after_files=after,
stdout_artifact_id=stdout_artifact.artifact_id,
stderr_artifact_id=stderr_artifact.artifact_id,
stdout_sha256=hashlib.sha256(safe_stdout.encode("utf-8")).hexdigest(),
stderr_sha256=hashlib.sha256(safe_stderr.encode("utf-8")).hexdigest(),
exit_code=exit_code,
command_ok=command_ok,
status="exited" if exit_code is not None else "failed_to_start",
created_unix_ms=started,
finished_unix_ms=finished,
)
_atomic_json(
_record_path(self.root, record.reproduction_id, "rep"),
record.to_dict(),
)
return record, safe_stdout, safe_stderr
def get(self, reproduction_id: str, *, session_id: str) -> ReproductionRecord:
payload = _load_payload(_record_path(self.root, reproduction_id, "rep"))
before = tuple(FileState(**row) for row in payload.pop("before_files", []))
after = tuple(FileState(**row) for row in payload.pop("after_files", []))
record = ReproductionRecord(
**payload,
before_files=before,
after_files=after,
)
_require_session(record.session_sha256, session_id)
return record
def compare(
self, reproduction_ids: tuple[str, ...], *, session_id: str
) -> dict[str, Any]:
if not reproduction_ids or len(reproduction_ids) != len(set(reproduction_ids)):
raise ValueError("reproduction ids must be non-empty and unique")
records = tuple(
self.get(identifier, session_id=session_id)
for identifier in reproduction_ids
)
def same(name: str) -> bool:
return len({getattr(record, name) for record in records}) == 1
return {
"reproduction_ids": list(reproduction_ids),
"same_command": same("command_sha256"),
"same_environment": same("environment_sha256"),
"same_exit_code": same("exit_code"),
"same_stdout": same("stdout_sha256"),
"same_stderr": same("stderr_sha256"),
"same_before_state": same("before_state_sha256"),
"same_after_state": same("after_state_sha256"),
"stable_outcome": all(
same(name)
for name in ("exit_code", "stdout_sha256", "stderr_sha256")
),
"state_drift_observed": not same("after_state_sha256"),
}
class TriageStore:
def __init__(self, workspace: str | Path) -> None:
self.workspace = ensure_control_root(workspace)
self.root = control_root(self.workspace) / "engineering" / "triage"
self.root.mkdir(parents=True, exist_ok=True, mode=0o700)
os.chmod(self.root, 0o700)
self.reproductions = ReproductionStore(self.workspace)
def create(
self,
*,
reproduction_ids: tuple[str, ...],
observed_facts: tuple[str, ...],
hypotheses: tuple[str, ...],
severity: str,
confidence: float,
next_actions: tuple[str, ...],
session_id: str,
) -> TriageRecord:
if not reproduction_ids or len(reproduction_ids) != len(set(reproduction_ids)):
raise ValueError("triage requires unique reproduction evidence")
if not observed_facts:
raise ValueError("triage requires at least one observed fact")
if severity not in _SEVERITIES:
raise ValueError("triage severity is invalid")
if confidence < 0.0 or confidence > 1.0:
raise ValueError("triage confidence must be between zero and one")
records = tuple(
self.reproductions.get(identifier, session_id=session_id)
for identifier in reproduction_ids
)
evidence = [
{
"id": record.reproduction_id,
"command": record.command_sha256,
"environment": record.environment_sha256,
"exit_code": record.exit_code,
"stdout": record.stdout_sha256,
"stderr": record.stderr_sha256,
"before": record.before_state_sha256,
"after": record.after_state_sha256,
}
for record in records
]
evidence_sha256 = hashlib.sha256(
json.dumps(evidence, sort_keys=True, separators=(",", ":")).encode(
"utf-8"
)
).hexdigest()
def sanitize(value: str) -> str:
return _sanitize(value, self.workspace)
record = TriageRecord(
triage_id="tri_" + secrets.token_hex(16),
session_sha256=_session_sha256(session_id),
reproduction_ids=reproduction_ids,
observed_facts=tuple(sanitize(item) for item in observed_facts),
hypotheses=tuple(sanitize(item) for item in hypotheses),
severity=severity,
confidence=confidence,
next_actions=tuple(sanitize(item) for item in next_actions),
evidence_sha256=evidence_sha256,
created_unix_ms=int(time.time() * 1000),
)
_atomic_json(_record_path(self.root, record.triage_id, "tri"), record.to_dict())
return record
def get(self, triage_id: str, *, session_id: str) -> TriageRecord:
payload = _load_payload(_record_path(self.root, triage_id, "tri"))
record = TriageRecord(
**{
**payload,
"reproduction_ids": tuple(payload.get("reproduction_ids", [])),
"observed_facts": tuple(payload.get("observed_facts", [])),
"hypotheses": tuple(payload.get("hypotheses", [])),
"next_actions": tuple(payload.get("next_actions", [])),
}
)
_require_session(record.session_sha256, session_id)
return record
def status(self, triage_id: str, *, session_id: str) -> dict[str, Any]:
record = self.get(triage_id, session_id=session_id)
evidence: list[dict[str, Any]] = []
for identifier in record.reproduction_ids:
reproduction = self.reproductions.get(
identifier, session_id=session_id
)
evidence.append(
{
"id": reproduction.reproduction_id,
"exit_code": reproduction.exit_code,
"command_ok": reproduction.command_ok,
"status": reproduction.status,
"state_drift_observed": reproduction.before_state_sha256
!= reproduction.after_state_sha256,
"stdout": reproduction.stdout_sha256,
"stderr": reproduction.stderr_sha256,
}
)
return {
**record.to_dict(),
"evidence": evidence,
"state_drift_observed": any(
item["state_drift_observed"] for item in evidence
),
}
def update(
self,
triage_id: str,
*,
reproduction_ids: tuple[str, ...],
observed_facts: tuple[str, ...],
hypotheses: tuple[str, ...],
severity: str,
confidence: float,
next_actions: tuple[str, ...],
session_id: str,
) -> TriageRecord:
record = self.get(triage_id, session_id=session_id)
if severity not in _SEVERITIES:
raise ValueError("triage severity is invalid")
if confidence < 0.0 or confidence > 1.0:
raise ValueError("triage confidence must be between zero and one")
merged_reproductions = _append_unique(record.reproduction_ids, reproduction_ids)
if not merged_reproductions:
raise ValueError("triage requires reproduction evidence")
records = tuple(
self.reproductions.get(identifier, session_id=session_id)
for identifier in merged_reproductions
)
evidence = [
{
"id": row.reproduction_id,
"command": row.command_sha256,
"environment": row.environment_sha256,
"exit_code": row.exit_code,
"stdout": row.stdout_sha256,
"stderr": row.stderr_sha256,
"before": row.before_state_sha256,
"after": row.after_state_sha256,
}
for row in records
]
updated = TriageRecord(
triage_id=record.triage_id,
session_sha256=record.session_sha256,
reproduction_ids=merged_reproductions,
observed_facts=_append_unique(
record.observed_facts,
tuple(_sanitize(item, self.workspace) for item in observed_facts),
),
hypotheses=_append_unique(
record.hypotheses,
tuple(_sanitize(item, self.workspace) for item in hypotheses),
),
severity=severity,
confidence=confidence,
next_actions=_append_unique(
record.next_actions,
tuple(_sanitize(item, self.workspace) for item in next_actions),
),
evidence_sha256=hashlib.sha256(
json.dumps(evidence, sort_keys=True, separators=(",", ":")).encode(
"utf-8"
)
).hexdigest(),
created_unix_ms=record.created_unix_ms,
)
_atomic_json(_record_path(self.root, updated.triage_id, "tri"), updated.to_dict())
return updated
class PatchStore:
def __init__(self, workspace: str | Path) -> None:
self.workspace = ensure_control_root(workspace)
self.root = control_root(self.workspace) / "engineering" / "patches"
self.root.mkdir(parents=True, exist_ok=True, mode=0o700)
os.chmod(self.root, 0o700)
self.triage = TriageStore(self.workspace)
self.reproductions = ReproductionStore(self.workspace)
self.transactions = TransactionStore(self.workspace)
def _write(self, record: PatchRecord) -> None:
_atomic_json(_record_path(self.root, record.patch_id, "patch"), record.to_dict())
def get(self, patch_id: str, *, session_id: str) -> PatchRecord:
payload = _load_payload(_record_path(self.root, patch_id, "patch"))
mutations = tuple(PatchMutation(**row) for row in payload.pop("mutations", []))
record = PatchRecord(
**{
**payload,
"paths": tuple(payload.get("paths", [])),
"verification_ids": tuple(payload.get("verification_ids", [])),
"mutations": mutations,
}
)
_require_session(record.session_sha256, session_id)
return record
def begin(
self, *, triage_id: str, paths: tuple[str, ...], session_id: str
) -> PatchRecord:
self.triage.get(triage_id, session_id=session_id)
if not paths or len(paths) != len(set(paths)):
raise ValueError("patch paths must be non-empty and unique")
transaction = self.transactions.begin(paths, session_id=session_id)
now = int(time.time() * 1000)
record = PatchRecord(
patch_id="patch_" + secrets.token_hex(16),
session_sha256=_session_sha256(session_id),
triage_id=triage_id,
transaction_id=transaction.transaction_id,
paths=tuple(entry.path for entry in transaction.entries),
status="open",
mutations=(),
verification_ids=(),
verified_state_sha256="",
last_error="",
created_unix_ms=now,
updated_unix_ms=now,
)
self._write(record)
return record
def _current_digests(self, paths: tuple[str, ...]) -> dict[str, str]:
current: dict[str, str] = {}
for raw_path in paths:
target = _contained_path(self.workspace, raw_path)
current[raw_path] = (
_sha256_file(target)[0] if target.is_file() else "missing"
)
return current
def _covered_state(self, paths: tuple[str, ...]) -> str:
states = tuple(
FileState(path, digest, 0)
for path, digest in sorted(self._current_digests(paths).items())
)
return _state_sha256(states)
def apply(
self,
patch_id: str,
changes: Sequence[Mapping[str, object]],
*,
session_id: str,
) -> tuple[PatchRecord, str]:
record = self.get(patch_id, session_id=session_id)
if record.status not in {"open", "applied", "verification_failed"}:
raise RuntimeError(f"patch is already {record.status}")
if not changes:
raise ValueError("patch changes must not be empty")
changed_paths: set[str] = set()
mutations: list[PatchMutation] = list(record.mutations)
error = ""
try:
for change in changes:
if not isinstance(change, Mapping):
raise ValueError("each patch change must be an object")
operation = str(change.get("operation") or "")
path = str(change.get("path") or "")
if path not in record.paths:
raise ValueError("patch change path is not covered by the transaction")
if path in changed_paths:
raise ValueError("each path may appear once per patch application")
changed_paths.add(path)
expected = str(change.get("expected_sha256") or "")
if expected and not _SHA256_RE.fullmatch(expected):
raise ValueError("expected_sha256 is invalid")
if operation == "replace":
if not expected:
raise ValueError("replace changes require expected_sha256")
result = atomic_patch_text(
self.workspace,
path,
expected_sha256=expected,
old_text=str(change.get("old_text") or ""),
new_text=str(change.get("new_text") or ""),
)
elif operation == "write":
result = atomic_write_text(
self.workspace,
path,
str(change.get("content") or ""),
expected_sha256=expected or None,
)
else:
raise ValueError("patch operation must be replace or write")
mutations.append(
PatchMutation(
operation=operation,
path=result.path,
before_sha256=result.before_sha256 or "missing",
after_sha256=result.after_sha256,
bytes=result.bytes,
created=result.created,
)
)
except (OSError, RuntimeError, UnicodeError, ValueError) as exc:
error = _sanitize(f"{type(exc).__name__}: {exc}", self.workspace)
status = "rolled_back"
try:
self.transactions.rollback(
record.transaction_id,
self._current_digests(record.paths),
session_id=session_id,
)
except (OSError, RuntimeError, ValueError) as rollback_exc:
status = "rollback_failed"
error += "; rollback: " + _sanitize(
f"{type(rollback_exc).__name__}: {rollback_exc}",
self.workspace,
)
failed = PatchRecord(
**{
**record.to_dict(),
"status": status,
"mutations": tuple(mutations),
"last_error": error,
"updated_unix_ms": int(time.time() * 1000),
}
)
self._write(failed)
return failed, error
updated = PatchRecord(
**{
**record.to_dict(),
"status": "applied",
"mutations": tuple(mutations),
"verified_state_sha256": "",
"last_error": "",
"updated_unix_ms": int(time.time() * 1000),
}
)
self._write(updated)
return updated, ""
def verify(
self,
patch_id: str,
*,
command: str,
working_directory: str,
timeout_s: float,
session_id: str,
run_command: RunCommand,
) -> tuple[PatchRecord, ReproductionRecord, str, str]:
record = self.get(patch_id, session_id=session_id)
if record.status not in {"applied", "verification_failed"}:
raise RuntimeError("patch must be applied before verification")
reproduction, stdout, stderr = self.reproductions.run(
command=command,
working_directory=working_directory,
snapshot_paths=record.paths,
timeout_s=timeout_s,
session_id=session_id,
run_command=run_command,
)
passed = reproduction.command_ok and reproduction.exit_code == 0
updated = PatchRecord(
**{
**record.to_dict(),
"status": "verified" if passed else "verification_failed",
"verification_ids": (*record.verification_ids, reproduction.reproduction_id),
"verified_state_sha256": self._covered_state(record.paths)
if passed
else "",
"last_error": "" if passed else "verification command did not succeed",
"updated_unix_ms": int(time.time() * 1000),
}
)
self._write(updated)
return updated, reproduction, stdout, stderr
def commit(self, patch_id: str, *, session_id: str) -> PatchRecord:
record = self.get(patch_id, session_id=session_id)
if record.status != "verified":
raise RuntimeError("patch must have successful current verification")
current_state = self._covered_state(record.paths)
if not hmac.compare_digest(current_state, record.verified_state_sha256):
raise RuntimeError("covered files changed after patch verification")
self.transactions.commit(record.transaction_id, session_id=session_id)
updated = PatchRecord(
**{
**record.to_dict(),
"status": "committed",
"updated_unix_ms": int(time.time() * 1000),
}
)
self._write(updated)
return updated
def require_current_verification(
self, patch_id: str, *, session_id: str
) -> PatchRecord:
record = self.get(patch_id, session_id=session_id)
if record.status not in {"verified", "committed"}:
raise ValueError("public disclosure requires a verified or committed patch")
current_state = self._covered_state(record.paths)
if not record.verified_state_sha256 or not hmac.compare_digest(
current_state, record.verified_state_sha256
):
raise RuntimeError("covered files changed after patch verification")
return record
def rollback(self, patch_id: str, *, session_id: str) -> PatchRecord:
record = self.get(patch_id, session_id=session_id)
if record.status == "rolled_back":
return record
if record.status == "rollback_failed":
raise RuntimeError("automatic rollback failed; inspect current file state")
self.transactions.rollback(
record.transaction_id,
self._current_digests(record.paths),
session_id=session_id,
)
transaction = self.transactions.get(
record.transaction_id, session_id=session_id
)
restored = self._current_digests(record.paths)
for entry in transaction.entries:
if not hmac.compare_digest(restored[entry.path], entry.sha256):
raise RuntimeError("rollback restoration proof failed")
restoration_sha256 = _state_sha256(
tuple(
FileState(path, digest, 0)
for path, digest in sorted(restored.items())
)
)
updated = PatchRecord(
**{
**record.to_dict(),
"status": "rolled_back",
"verified_state_sha256": "",
"restoration_sha256": restoration_sha256,
"updated_unix_ms": int(time.time() * 1000),
}
)
self._write(updated)
return updated
class DisclosureStore:
def __init__(self, workspace: str | Path) -> None:
self.workspace = ensure_control_root(workspace)
self.root = control_root(self.workspace) / "engineering" / "disclosures"
self.root.mkdir(parents=True, exist_ok=True, mode=0o700)
os.chmod(self.root, 0o700)
self.triage = TriageStore(self.workspace)
self.patches = PatchStore(self.workspace)
self.artifacts = ArtifactStore(self.workspace)
def create(
self,
*,
triage_id: str,
title: str,
summary: str,
impact: str,
remediation: str,
audience: str,
patch_id: str,
session_id: str,
) -> DisclosureRecord:
triage = self.triage.get(triage_id, session_id=session_id)
if audience not in _AUDIENCES:
raise ValueError("disclosure audience is invalid")
fields = tuple(
_sanitize(value, self.workspace)
for value in (title, summary, impact, remediation)
)
if any(not value.strip() for value in fields):
raise ValueError("disclosure fields must not be empty")
patch = self.patches.get(patch_id, session_id=session_id) if patch_id else None
if audience == "public":
if patch is None:
raise ValueError(
"public disclosure requires a verified or committed patch"
)
patch = self.patches.require_current_verification(
patch.patch_id, session_id=session_id
)
evidence = {
"triage": triage.evidence_sha256,
"reproductions": list(triage.reproduction_ids),
"patch": {
"id": patch.patch_id,
"status": patch.status,
"verification_ids": list(patch.verification_ids),
"mutations": [
{
"before": mutation.before_sha256,
"after": mutation.after_sha256,
}
for mutation in patch.mutations
],
}
if patch is not None
else None,
}
evidence_sha256 = hashlib.sha256(
json.dumps(evidence, sort_keys=True, separators=(",", ":")).encode(
"utf-8"
)
).hexdigest()
fact_lines = "\n".join(f"- {fact}" for fact in triage.observed_facts)
hypothesis_lines = "\n".join(
f"- {hypothesis}" for hypothesis in triage.hypotheses
) or "- None recorded"
patch_section = ""
if patch is not None:
patch_section = (
"\n## Repair Evidence\n"
f"- Status: {patch.status}\n"
f"- Changed files: {len({mutation.path for mutation in patch.mutations})}\n"
f"- Verification receipts: {', '.join(patch.verification_ids) or 'none'}\n"
)
document = (
f"# {fields[0]}\n\n"
f"Audience: {audience}\n\n"
"## Summary\n"
f"{fields[1]}\n\n"
"## Impact\n"
f"{fields[2]}\n\n"
"## Observed Facts\n"
f"{fact_lines}\n\n"
"## Hypotheses\n"
f"{hypothesis_lines}\n\n"
"## Evidence\n"
f"- Evidence digest: {evidence_sha256}\n"
f"- Reproduction receipts: {', '.join(triage.reproduction_ids)}\n"
f"- Severity: {triage.severity}\n"
f"- Confidence: {triage.confidence:.3f}\n"
f"{patch_section}\n"
"## Remediation\n"
f"{fields[3]}\n\n"
"Raw command output, credentials, absolute workspace paths, private session identifiers, and internal control state are omitted.\n"
)
artifact = self.artifacts.put_text(
document,
media_type="text/markdown; charset=utf-8",
source="sanitized_disclosure",
session_id=session_id or "direct",
)
record = DisclosureRecord(
disclosure_id="dis_" + secrets.token_hex(16),
session_sha256=_session_sha256(session_id),
triage_id=triage_id,
patch_id=patch_id,
audience=audience,
evidence_sha256=evidence_sha256,
artifact_id=artifact.artifact_id,
artifact_sha256=artifact.sha256,
created_unix_ms=int(time.time() * 1000),
)
_atomic_json(
_record_path(self.root, record.disclosure_id, "dis"), record.to_dict()
)
return record
def get(self, disclosure_id: str, *, session_id: str) -> DisclosureRecord:
payload = _load_payload(_record_path(self.root, disclosure_id, "dis"))
record = DisclosureRecord(**payload)
_require_session(record.session_sha256, session_id)
return record
class EvidenceBundleStore:
def __init__(self, workspace: str | Path) -> None:
self.workspace = ensure_control_root(workspace)
self.root = control_root(self.workspace) / "engineering" / "bundles"
self.root.mkdir(parents=True, exist_ok=True, mode=0o700)
os.chmod(self.root, 0o700)
self.reproductions = ReproductionStore(self.workspace)
self.triage = TriageStore(self.workspace)
self.disclosures = DisclosureStore(self.workspace)
self.patches = PatchStore(self.workspace)
self.artifacts = ArtifactStore(self.workspace)
def create(
self,
*,
title: str,
reproduction_ids: tuple[str, ...],
triage_ids: tuple[str, ...],
disclosure_ids: tuple[str, ...],
patch_ids: tuple[str, ...],
session_id: str,
) -> EvidenceBundleRecord:
safe_title = _sanitize(title, self.workspace).strip()
if not safe_title:
raise ValueError("evidence bundle title is required")
if not any((reproduction_ids, triage_ids, disclosure_ids, patch_ids)):
raise ValueError("evidence bundle requires at least one receipt id")
if any(
len(rows) != len(set(rows))
for rows in (reproduction_ids, triage_ids, disclosure_ids, patch_ids)
):
raise ValueError("evidence bundle receipt ids must be unique per type")
reproductions = tuple(
self.reproductions.get(identifier, session_id=session_id)
for identifier in reproduction_ids
)
triages = tuple(
self.triage.status(identifier, session_id=session_id)
for identifier in triage_ids
)
disclosures = tuple(
self.disclosures.get(identifier, session_id=session_id)
for identifier in disclosure_ids
)
patches = tuple(
self.patches.get(identifier, session_id=session_id)
for identifier in patch_ids
)
evidence = {
"reproductions": [
{
"id": record.reproduction_id,
"command": record.command_sha256,
"environment": record.environment_sha256,
"exit_code": record.exit_code,
"status": record.status,
"stdout": record.stdout_sha256,
"stderr": record.stderr_sha256,
"before": record.before_state_sha256,
"after": record.after_state_sha256,
}
for record in reproductions
],
"triage": [
{
"id": str(row["triage_id"]),
"evidence": str(row["evidence_sha256"]),
"severity": str(row["severity"]),
"confidence": float(row["confidence"]),
"state_drift_observed": bool(row["state_drift_observed"]),
}
for row in triages
],
"disclosures": [
{
"id": record.disclosure_id,
"triage": record.triage_id,
"patch": record.patch_id,
"audience": record.audience,
"artifact": record.artifact_id,
"artifact_sha256": record.artifact_sha256,
}
for record in disclosures
],
"patches": [
{
"id": record.patch_id,
"triage": record.triage_id,
"status": record.status,
"paths": len(record.paths),
"mutations": len(record.mutations),
"verification_ids": list(record.verification_ids),
"verified_state": record.verified_state_sha256,
"restoration": record.restoration_sha256,
}
for record in patches
],
}
evidence_sha256 = hashlib.sha256(
json.dumps(evidence, sort_keys=True, separators=(",", ":")).encode(
"utf-8"
)
).hexdigest()
document = (
f"# {safe_title}\n\n"
f"Evidence digest: {evidence_sha256}\n\n"
"## Reproductions\n"
+ "\n".join(
(
f"- {record.reproduction_id}: status={record.status}, "
f"exit={record.exit_code}, stdout={record.stdout_sha256}, "
f"stderr={record.stderr_sha256}"
)
for record in reproductions
)
+ ("\n" if reproductions else "- None\n")
+ "\n## Triage\n"
+ "\n".join(
(
f"- {row['triage_id']}: severity={row['severity']}, "
f"confidence={float(row['confidence']):.3f}, "
f"evidence={row['evidence_sha256']}"
)
for row in triages
)
+ ("\n" if triages else "- None\n")
+ "\n## Disclosures\n"
+ "\n".join(
(
f"- {record.disclosure_id}: audience={record.audience}, "
f"artifact={record.artifact_id}, sha256={record.artifact_sha256}"
)
for record in disclosures
)
+ ("\n" if disclosures else "- None\n")
+ "\n## Patches\n"
+ "\n".join(
(
f"- {record.patch_id}: status={record.status}, "
f"mutations={len(record.mutations)}, "
f"verification={','.join(record.verification_ids) or 'none'}"
)
for record in patches
)
+ ("\n" if patches else "- None\n")
+ "\nRaw command output, credentials, absolute workspace paths, private session identifiers, and internal control state are omitted.\n"
)
artifact = self.artifacts.put_text(
document,
media_type="text/markdown; charset=utf-8",
source="sanitized_evidence_bundle",
session_id=session_id or "direct",
)
record = EvidenceBundleRecord(
bundle_id="evb_" + secrets.token_hex(16),
session_sha256=_session_sha256(session_id),
title=safe_title,
reproduction_ids=reproduction_ids,
triage_ids=triage_ids,
disclosure_ids=disclosure_ids,
patch_ids=patch_ids,
evidence_sha256=evidence_sha256,
artifact_id=artifact.artifact_id,
artifact_sha256=artifact.sha256,
created_unix_ms=int(time.time() * 1000),
)
_atomic_json(_record_path(self.root, record.bundle_id, "evb"), record.to_dict())
return record
def get(self, bundle_id: str, *, session_id: str) -> EvidenceBundleRecord:
payload = _load_payload(_record_path(self.root, bundle_id, "evb"))
record = EvidenceBundleRecord(
**{
**payload,
"reproduction_ids": tuple(payload.get("reproduction_ids", [])),
"triage_ids": tuple(payload.get("triage_ids", [])),
"disclosure_ids": tuple(payload.get("disclosure_ids", [])),
"patch_ids": tuple(payload.get("patch_ids", [])),
}
)
_require_session(record.session_sha256, session_id)
return record
def _tool_result(
call: ToolCall,
*,
started: float,
ok: bool,
output: str = "",
error: str = "",
exit_code: int | None = None,
) -> ToolExecutionResult:
rendered = output or error
return ToolExecutionResult(
name=call.name,
args=call.args,
ok=ok,
tool_call_id=call.call_id,
output=output,
error=error,
exit_code=exit_code,
executed=True,
elapsed_s=round(time.perf_counter() - started, 4),
source_trust="trusted_execution",
output_sha256=hashlib.sha256(rendered.encode("utf-8")).hexdigest(),
)
def execute_engineering_tool(
call: ToolCall,
context: ToolExecutionContext,
*,
run_command: RunCommand,
) -> ToolExecutionResult:
"""Execute one evidence-bound engineering tool at the runtime boundary."""
started = time.perf_counter()
spec = _ENGINEERING_TOOL_BY_NAME.get(call.name)
if spec is None:
return _tool_result(
call,
started=started,
ok=False,
error=f"unsupported engineering tool: {call.name}",
)
try:
spec.validate_arguments(call.args)
workspace = context.workspace
session_id = context.session_id
if call.name == "ReproductionRun":
reproduction_record, stdout, stderr = ReproductionStore(workspace).run(
command=str(call.args["command"]),
working_directory=str(call.args.get("working_directory") or "."),
snapshot_paths=_string_tuple(
call.args.get("snapshot_paths", []), "snapshot_paths"
),
timeout_s=context.timeout_s,
session_id=session_id,
run_command=run_command,
)
output = json.dumps(
{
"record": reproduction_record.to_dict(),
"stdout": stdout,
"stderr": stderr,
},
sort_keys=True,
)
return _tool_result(
call,
started=started,
ok=reproduction_record.exit_code is not None,
output=output,
exit_code=reproduction_record.exit_code,
)
if call.name == "ReproductionCompare":
comparison = ReproductionStore(workspace).compare(
_string_tuple(
call.args["reproduction_ids"],
"reproduction_ids",
allow_empty=False,
),
session_id=session_id,
)
return _tool_result(
call,
started=started,
ok=True,
output=json.dumps(comparison, sort_keys=True),
)
if call.name == "TriageCreate":
triage_record = TriageStore(workspace).create(
reproduction_ids=_string_tuple(
call.args["reproduction_ids"],
"reproduction_ids",
allow_empty=False,
),
observed_facts=_string_tuple(
call.args["observed_facts"],
"observed_facts",
allow_empty=False,
),
hypotheses=_string_tuple(call.args["hypotheses"], "hypotheses"),
severity=str(call.args["severity"]),
confidence=float(call.args["confidence"]),
next_actions=_string_tuple(
call.args["next_actions"], "next_actions"
),
session_id=session_id,
)
return _tool_result(
call,
started=started,
ok=True,
output=json.dumps(triage_record.to_dict(), sort_keys=True),
)
if call.name == "TriageStatus":
triage_status = TriageStore(workspace).status(
str(call.args["triage_id"]), session_id=session_id
)
return _tool_result(
call,
started=started,
ok=True,
output=json.dumps(triage_status, sort_keys=True),
)
if call.name == "TriageUpdate":
raw_confidence = call.args.get("confidence")
current = TriageStore(workspace).get(
str(call.args["triage_id"]), session_id=session_id
)
triage_record = TriageStore(workspace).update(
str(call.args["triage_id"]),
reproduction_ids=_string_tuple(
call.args.get("reproduction_ids", []),
"reproduction_ids",
),
observed_facts=_string_tuple(
call.args.get("observed_facts", []), "observed_facts"
),
hypotheses=_string_tuple(call.args.get("hypotheses", []), "hypotheses"),
severity=str(call.args.get("severity") or current.severity),
confidence=float(raw_confidence)
if raw_confidence is not None
else current.confidence,
next_actions=_string_tuple(
call.args.get("next_actions", []), "next_actions"
),
session_id=session_id,
)
return _tool_result(
call,
started=started,
ok=True,
output=json.dumps(triage_record.to_dict(), sort_keys=True),
)
if call.name == "DisclosureCreate":
disclosure_record = DisclosureStore(workspace).create(
triage_id=str(call.args["triage_id"]),
title=str(call.args["title"]),
summary=str(call.args["summary"]),
impact=str(call.args["impact"]),
remediation=str(call.args["remediation"]),
audience=str(call.args.get("audience") or "maintainer"),
patch_id=str(call.args.get("patch_id") or ""),
session_id=session_id,
)
return _tool_result(
call,
started=started,
ok=True,
output=json.dumps(disclosure_record.to_dict(), sort_keys=True),
)
if call.name == "DisclosureStatus":
disclosure_record = DisclosureStore(workspace).get(
str(call.args["disclosure_id"]), session_id=session_id
)
return _tool_result(
call,
started=started,
ok=True,
output=json.dumps(disclosure_record.to_dict(), sort_keys=True),
)
if call.name == "EvidenceBundleCreate":
bundle_record = EvidenceBundleStore(workspace).create(
title=str(call.args["title"]),
reproduction_ids=_string_tuple(
call.args.get("reproduction_ids", []), "reproduction_ids"
),
triage_ids=_string_tuple(call.args.get("triage_ids", []), "triage_ids"),
disclosure_ids=_string_tuple(
call.args.get("disclosure_ids", []), "disclosure_ids"
),
patch_ids=_string_tuple(call.args.get("patch_ids", []), "patch_ids"),
session_id=session_id,
)
return _tool_result(
call,
started=started,
ok=True,
output=json.dumps(bundle_record.to_dict(), sort_keys=True),
)
if call.name == "EvidenceBundleStatus":
bundle_record = EvidenceBundleStore(workspace).get(
str(call.args["bundle_id"]), session_id=session_id
)
return _tool_result(
call,
started=started,
ok=True,
output=json.dumps(bundle_record.to_dict(), sort_keys=True),
)
patches = PatchStore(workspace)
if call.name == "PatchBegin":
patch_record = patches.begin(
triage_id=str(call.args["triage_id"]),
paths=_string_tuple(
call.args["paths"], "paths", allow_empty=False
),
session_id=session_id,
)
elif call.name == "PatchApply":
raw_changes = call.args["changes"]
if not isinstance(raw_changes, list):
raise ValueError("changes must be an array")
patch_record, error = patches.apply(
str(call.args["patch_id"]),
tuple(raw_changes),
session_id=session_id,
)
return _tool_result(
call,
started=started,
ok=not error,
output=json.dumps(patch_record.to_dict(), sort_keys=True),
error=error,
)
elif call.name == "PatchVerify":
patch_record, verification_record, stdout, stderr = patches.verify(
str(call.args["patch_id"]),
command=str(call.args["command"]),
working_directory=str(call.args.get("working_directory") or "."),
timeout_s=context.timeout_s,
session_id=session_id,
run_command=run_command,
)
output = json.dumps(
{
"patch": patch_record.to_dict(),
"reproduction": verification_record.to_dict(),
"stdout": stdout,
"stderr": stderr,
},
sort_keys=True,
)
return _tool_result(
call,
started=started,
ok=patch_record.status == "verified",
output=output,
error=patch_record.last_error,
exit_code=verification_record.exit_code,
)
elif call.name == "PatchCommit":
patch_record = patches.commit(
str(call.args["patch_id"]), session_id=session_id
)
elif call.name == "PatchRollback":
patch_record = patches.rollback(
str(call.args["patch_id"]), session_id=session_id
)
elif call.name == "PatchStatus":
patch_record = patches.get(
str(call.args["patch_id"]), session_id=session_id
)
else:
raise RuntimeError("engineering tool dispatch is incomplete")
return _tool_result(
call,
started=started,
ok=True,
output=json.dumps(patch_record.to_dict(), sort_keys=True),
)
except (OSError, PermissionError, RuntimeError, TypeError, ValueError) as exc:
return _tool_result(
call,
started=started,
ok=False,
error=f"{type(exc).__name__}: {exc}",
)
__all__ = [
"DisclosureRecord",
"DisclosureStore",
"ENGINEERING_TOOL_NAMES",
"ENGINEERING_TOOL_SPECS",
"EvidenceBundleRecord",
"EvidenceBundleStore",
"FileState",
"PatchMutation",
"PatchRecord",
"PatchStore",
"ReproductionRecord",
"ReproductionStore",
"TriageRecord",
"TriageStore",
"execute_engineering_tool",
]