Harness foundation: INTENT, ADR-001, architecture, prototype adoption

- INTENT.md: three-layer model (blueprint/instance/harness), single
  shared runtime, never-become boundaries
- ADR-001 (accepted): DEC-2026-002 resolution — one harness repo for
  all projects; instances are declarative state in consuming repos
- docs/architecture.md: components, contracts (manifest, tool
  profiles, completion events, credential lanes), deployment shape
- agent_harness/: executor-worker prototype adopted and renamed
  (6/6 tests green); HARNESS-WP-0001 initial workplan (7 tasks)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-07-17 23:35:27 +02:00
parent 87ae78c56a
commit cfc1b75157
18 changed files with 1204 additions and 1 deletions

117
tests/test_mailscan.py Normal file
View file

@ -0,0 +1,117 @@
from __future__ import annotations
import subprocess
from pathlib import Path
import pytest
from agent_harness import mailscan
class FakeCompleted:
def __init__(self, returncode=0, stdout="", stderr=""):
self.returncode = returncode
self.stdout = stdout
self.stderr = stderr
def _repo_with_reports(tmp_path: Path, names: list[str]) -> Path:
repo = tmp_path / "binky-control"
(repo / "mailmeta" / "reports").mkdir(parents=True)
for name in names:
(repo / "mailmeta" / "reports" / name).write_text("header\nrow1\nrow2\n")
return repo
def test_mail_scan_approle_lane_and_new_report(tmp_path, monkeypatch) -> None:
repo = _repo_with_reports(tmp_path, ["old.csv"])
approle = tmp_path / "approle"
approle.mkdir()
(approle / "role_id").write_text("rid\n")
(approle / "secret_id").write_text("sid\n")
monkeypatch.setenv("EXECUTOR_APPROLE_DIR", str(approle))
calls: list[list[str]] = []
def fake_run(cmd, **kwargs):
calls.append(cmd)
if cmd[0] == "bao" and cmd[1] == "write":
assert "auth/approle/login" in cmd
return FakeCompleted(stdout="tok123\n")
if cmd[0] == "bao" and cmd[1] == "kv":
assert kwargs["env"]["BAO_TOKEN"] == "tok123"
return FakeCompleted(stdout="value\n")
if cmd[1] == "-m": # python3 -m email_connect.cli ...
env = kwargs["env"]
assert env["IMAP_USERNAME"] == "value"
assert env["IMAP_PASSWORD"] == "value"
(repo / "mailmeta" / "reports" / "new-report.csv").write_text(
"header\na\nb\nc\n"
)
return FakeCompleted()
raise AssertionError(f"unexpected command: {cmd}")
monkeypatch.setattr(subprocess, "run", fake_run)
events: list[dict] = []
monkeypatch.setattr(
mailscan.hub,
"post_progress_event",
lambda **kw: events.append(kw) or True,
)
result = mailscan.run_mail_scan(repo)
assert result.ok is True
assert result.auth_lane == "approle"
assert result.report_path == "new-report.csv"
assert result.new_messages == 3
assert events[0]["event_type"] == "binky_mail_intake"
# secret values must never appear in the hub event
assert "value" not in str(events[0]["detail"])
def test_mail_scan_failure_does_not_emit_intake_event(tmp_path, monkeypatch) -> None:
repo = _repo_with_reports(tmp_path, [])
monkeypatch.delenv("EXECUTOR_APPROLE_DIR", raising=False)
def fake_run(cmd, **kwargs):
if cmd[0] == "bao":
return FakeCompleted(stdout="value\n")
return FakeCompleted(returncode=3, stderr="imap connect refused")
monkeypatch.setattr(subprocess, "run", fake_run)
events: list[dict] = []
monkeypatch.setattr(
mailscan.hub,
"post_progress_event",
lambda **kw: events.append(kw) or True,
)
result = mailscan.run_mail_scan(repo)
assert result.ok is False
assert result.auth_lane == "ambient"
assert "exited 3" in result.reason
assert events[0]["event_type"] == "executor_run"
def test_mail_scan_reports_failure_when_bao_unavailable(tmp_path, monkeypatch) -> None:
repo = _repo_with_reports(tmp_path, [])
monkeypatch.delenv("EXECUTOR_APPROLE_DIR", raising=False)
def fake_run(cmd, **kwargs):
return FakeCompleted(returncode=2, stderr="permission denied")
monkeypatch.setattr(subprocess, "run", fake_run)
events: list[dict] = []
monkeypatch.setattr(
mailscan.hub,
"post_progress_event",
lambda **kw: events.append(kw) or True,
)
result = mailscan.run_mail_scan(repo)
assert result.ok is False
assert "bao kv failed" in result.reason
assert events[0]["event_type"] == "executor_run"

88
tests/test_runner.py Normal file
View file

@ -0,0 +1,88 @@
from __future__ import annotations
import subprocess
from pathlib import Path
import pytest
from agent_harness.runner import RunResult, run_task
from agent_harness.taskspec import TaskSpec, TaskSpecError
def _make_repo(tmp_path: Path) -> Path:
repo = tmp_path / "sandbox"
repo.mkdir()
subprocess.run(["git", "init", "-q"], cwd=repo, check=True)
(repo / "README.md").write_text("sandbox\n")
subprocess.run(["git", "add", "."], cwd=repo, check=True)
subprocess.run(
["git", "-c", "user.email=t@t", "-c", "user.name=t", "commit", "-qm", "init"],
cwd=repo,
check=True,
)
return repo
class CommittingAdapter:
"""Fake adapter that simulates a session which commits."""
def __init__(self, repo: Path):
self.repo = repo
self.prompts: list[str] = []
def execute_prompt(self, prompt, config):
self.prompts.append(prompt)
(self.repo / "HELLO.md").write_text("hello\n")
subprocess.run(["git", "add", "."], cwd=self.repo, check=True)
subprocess.run(
["git", "-c", "user.email=t@t", "-c", "user.name=t", "commit", "-qm", "task done"],
cwd=self.repo,
check=True,
)
from llm_connect.models import LLMResponse
return LLMResponse(content="done", model="fake", usage={}, finish_reason="stop")
class IdleAdapter:
def execute_prompt(self, prompt, config):
from llm_connect.models import LLMResponse
return LLMResponse(content="nothing to do", model="fake", usage={}, finish_reason="stop")
def _spec(repo: Path) -> TaskSpec:
return TaskSpec(title="write hello", description="create HELLO.md", target_repo=repo)
def test_run_task_success_when_session_commits(tmp_path) -> None:
repo = _make_repo(tmp_path)
adapter = CommittingAdapter(repo)
result = run_task(_spec(repo), adapter=adapter, report_to_hub=False)
assert isinstance(result, RunResult)
assert result.ok is True
assert result.committed is True
assert result.head_before != result.head_after
assert "write hello" in adapter.prompts[0]
assert "Never push" in adapter.prompts[0]
def test_run_task_fails_without_commit(tmp_path) -> None:
repo = _make_repo(tmp_path)
result = run_task(_spec(repo), adapter=IdleAdapter(), report_to_hub=False)
assert result.ok is False
assert result.committed is False
assert result.reason == "session completed without committing"
def test_taskspec_rejects_non_repo(tmp_path) -> None:
spec_file = tmp_path / "task.json"
spec_file.write_text(
'{"title": "x", "description": "y", "target_repo": "%s"}' % tmp_path
)
with pytest.raises(TaskSpecError, match="not a git repository"):
TaskSpec.from_file(spec_file)