feat(runtime): enforce governed mutation boundaries
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a06ba0-10aa-7ea0-b20a-4f3fac39efe9
This commit is contained in:
parent
e3c6124e22
commit
20e6f381f6
28 changed files with 1068 additions and 154 deletions
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
Flow: lock target repo → resolve tool profile / budget from instance
|
||||
manifest → snapshot HEAD → persona bundle → prompt → agentic session →
|
||||
verify a new commit exists → kaizen metrics + hub progress event
|
||||
(+ task close). The run *fails* if the session pushed anywhere or left
|
||||
the repo dirty in a way it should not — the worker never pushes;
|
||||
publishing is a separate, explicitly-granted lane.
|
||||
validate an explicit repository grant when present → metrics + hub progress
|
||||
event (+ task close). Granted runs use durable external metrics so repository
|
||||
acceptance remains clean. The worker never pushes; publishing is a separate,
|
||||
explicitly-granted lane.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
|
@ -24,6 +24,7 @@ from rein_aharness.profiles import UnknownToolProfileError, get_profile
|
|||
from rein_aharness.repository_transaction import (
|
||||
DirtyRepositoryError,
|
||||
GitRepositoryError,
|
||||
RepositoryAcceptanceError,
|
||||
RepositoryBusyError,
|
||||
RepositoryTransaction,
|
||||
RepositoryTransactionError,
|
||||
|
|
@ -116,11 +117,11 @@ def run_task(
|
|||
budget_tokens_override: int | None = None,
|
||||
transaction: RepositoryTransaction | None = None,
|
||||
) -> RunResult:
|
||||
if spec.repository_grant is not None:
|
||||
if spec.repository_grant is not None and not write_metrics:
|
||||
return _refused_run(
|
||||
reason=(
|
||||
"refused: repository_grant enforcement is not enabled; "
|
||||
"no adapter was dispatched"
|
||||
"refused: repository_grant runs require durable external metrics; "
|
||||
"--no-metrics is incompatible"
|
||||
),
|
||||
model=model,
|
||||
)
|
||||
|
|
@ -255,11 +256,62 @@ def _execute_locked_task(
|
|||
|
||||
head_after = _git(spec.target_repo, "rev-parse", "HEAD")
|
||||
committed = head_after != head_before
|
||||
if session_ok and spec.repository_grant is not None:
|
||||
try:
|
||||
tx.validate_acceptance(spec.repository_grant.acceptance_policy())
|
||||
except RepositoryAcceptanceError as exc:
|
||||
session_ok = False
|
||||
reason = str(exc)
|
||||
ok = session_ok and committed
|
||||
if session_ok and not committed:
|
||||
if session_ok and not committed and spec.repository_grant is None:
|
||||
reason = "session completed without committing"
|
||||
|
||||
tokens_spent = budget_tracker.spent if budget_tracker is not None else None
|
||||
transaction_evidence = tx.evidence()
|
||||
if spec.repository_grant is not None:
|
||||
transaction_evidence["repository_grant"] = spec.repository_grant.evidence()
|
||||
|
||||
metric_metadata = {
|
||||
"task_title": spec.title,
|
||||
"tool_profile": profile.name,
|
||||
"labels": list(spec.labels),
|
||||
"completion_event_type": spec.completion_event_type,
|
||||
}
|
||||
if spec.repository_grant is not None:
|
||||
metric_metadata["repository_grant_id"] = spec.repository_grant.grant_id
|
||||
|
||||
if write_metrics:
|
||||
try:
|
||||
recorder = (
|
||||
metrics.record_external_execution
|
||||
if spec.repository_grant is not None
|
||||
else metrics.record_execution
|
||||
)
|
||||
recorder(
|
||||
spec.target_repo,
|
||||
spec.agent,
|
||||
success=ok,
|
||||
execution_time_s=execution_time_s,
|
||||
tokens=tokens_spent,
|
||||
committed=committed,
|
||||
head_after=head_after,
|
||||
reason=reason or None,
|
||||
metadata=metric_metadata,
|
||||
session_id=tx.transaction_id,
|
||||
)
|
||||
if spec.repository_grant is not None:
|
||||
transaction_evidence["metrics"] = {
|
||||
"storage": "external",
|
||||
"session_id": tx.transaction_id,
|
||||
"projection_ready": True,
|
||||
}
|
||||
except OSError as exc:
|
||||
if spec.repository_grant is not None:
|
||||
ok = False
|
||||
reason = (
|
||||
"required external metrics persistence failed "
|
||||
f"({type(exc).__name__})"
|
||||
)
|
||||
|
||||
result = RunResult(
|
||||
ok=ok,
|
||||
|
|
@ -275,30 +327,9 @@ def _execute_locked_task(
|
|||
tokens_spent=tokens_spent,
|
||||
execution_time_s=execution_time_s,
|
||||
tool_events=collected_events,
|
||||
transaction=tx.evidence(),
|
||||
transaction=transaction_evidence,
|
||||
)
|
||||
|
||||
if write_metrics:
|
||||
try:
|
||||
metrics.record_execution(
|
||||
spec.target_repo,
|
||||
spec.agent,
|
||||
success=ok,
|
||||
execution_time_s=execution_time_s,
|
||||
tokens=tokens_spent,
|
||||
committed=committed,
|
||||
head_after=head_after,
|
||||
reason=reason or None,
|
||||
metadata={
|
||||
"task_title": spec.title,
|
||||
"tool_profile": profile.name,
|
||||
"labels": list(spec.labels),
|
||||
"completion_event_type": spec.completion_event_type,
|
||||
},
|
||||
)
|
||||
except OSError:
|
||||
pass # metrics must not block run completion reporting
|
||||
|
||||
if report_to_hub:
|
||||
detail = {
|
||||
"repo": spec.target_repo.name,
|
||||
|
|
@ -314,6 +345,7 @@ def _execute_locked_task(
|
|||
"budget_tokens": budget_tokens,
|
||||
"tokens_spent": tokens_spent,
|
||||
"execution_time_s": round(execution_time_s, 3),
|
||||
"repository_transaction": transaction_evidence,
|
||||
}
|
||||
hub.post_progress_event(
|
||||
summary=f"executor run: {spec.title} ({'ok' if ok else 'failed'})",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue