Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,21 @@ invart replay export --ledger ledger.jsonl --out replay.html
invart audit report --ledger ledger.jsonl --out-dir .invart/audit
```

### Real agent conformance

```bash
invart adapter profile --kind claude-code
invart real-agent check --agent claude-code --out-dir .invart/real-agent
invart real-agent report --run-dir .invart/real-agent --out .invart/real-agent/report.html
```

Use `--require-live` when you want missing local agent binaries to fail the run instead of being recorded as blocked evidence. Fixture-backed runs validate the Invart adapter contract; live runs validate the installed product surface.

### Evaluation

```bash
invart eval list
invart eval benchmark --suite full-product-readiness
invart eval benchmark --suite v0.9.3-agent-adapter-contract
invart roadmap status --require-full
```
4 changes: 4 additions & 0 deletions docs/html/cli-reference.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@
invart gate verify --proof proof.json --ledger ledger.jsonl --mode ci</pre></div>
<div class="card"><h3>Replay and audit</h3><pre>invart replay export --ledger ledger.jsonl --out replay.html
invart audit report --ledger ledger.jsonl --out-dir .invart/audit</pre></div>
<div class="card"><h3>Real agent conformance</h3><pre>invart adapter profile --kind claude-code
invart real-agent check --agent claude-code --out-dir .invart/real-agent
invart real-agent report --run-dir .invart/real-agent --out .invart/real-agent/report.html</pre><p>Use <code>--require-live</code> when missing local binaries should fail instead of being recorded as blocked evidence.</p></div>
<div class="card"><h3>Evaluation</h3><pre>invart eval list
invart eval benchmark --suite full-product-readiness
invart eval benchmark --suite v0.9.3-agent-adapter-contract
invart roadmap status --require-full</pre></div>
</section>
</main>
Expand Down
7 changes: 7 additions & 0 deletions docs/html/release-history.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ <h2>Pre-1.0 Research-Ready Track</h2>
<tr><td>v0.51</td><td>Implemented</td><td>Separate research-ready gate layered on top of product RC readiness.</td></tr>
</table>
</section>
<section>
<h2>0.9 Patch Track</h2>
<table>
<tr><th>Version</th><th>Status</th><th>Focus</th></tr>
<tr><td>v0.9.3</td><td>Implemented</td><td>Agent adapter contract registry and fixture-backed real-agent conformance foundation. The live mode can be strict, but missing local agent binaries are not reported as successful live validation.</td></tr>
</table>
</section>
<section>
<h2>Internal History</h2>
<p>Detailed historical roadmap and design pages live in <code>internal/history/docs/</code>. They are local-only planning material and are ignored by git for the open-source boundary.</p>
Expand Down
6 changes: 6 additions & 0 deletions docs/release-history.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ Invart has a long local implementation history. The public docs summarize capabi
| v0.50 | Implemented | Product control matrix showing why plugin-only coverage is not full runtime mediation. |
| v0.51 | Implemented | Separate research-ready gate layered on top of product RC readiness. |

## 0.9 Patch Track

| Version | Status | Focus |
| --- | --- | --- |
| v0.9.3 | Implemented | Agent adapter contract registry and fixture-backed real-agent conformance foundation. The live mode can be strict, but missing local agent binaries are not reported as successful live validation. |

## Internal History

Detailed historical roadmap and design pages live in internal/history/docs/. They are local-only planning material and are ignored by git for the open-source boundary.
2 changes: 2 additions & 0 deletions src/invart/benchmarks/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
run_product_control_matrix_benchmark,
run_reviewer_ablation_cost_benchmark,
)
from .releases_v52_v57 import run_agent_adapter_contract_benchmark

BenchmarkRunner = Callable[[], dict[str, Any]]

Expand Down Expand Up @@ -109,6 +110,7 @@ def benchmark_runner_registry() -> dict[str, BenchmarkRunner]:
"v0.49-reviewer-ablation-cost": run_reviewer_ablation_cost_benchmark,
"v0.50-product-control-matrix": run_product_control_matrix_benchmark,
"v0.51-pre-1.0-research-ready-gate": run_pre_1_0_research_ready_gate_benchmark,
"v0.9.3-agent-adapter-contract": run_agent_adapter_contract_benchmark,
"progressive-external-validation": run_progressive_external_validation_benchmark,
"real-world-agent-risk-demo": run_real_world_risk_benchmark,
"containerized-risk-demo": run_container_risk_demo_benchmark,
Expand Down
41 changes: 41 additions & 0 deletions src/invart/benchmarks/releases_v52_v57.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from __future__ import annotations

import tempfile
from pathlib import Path

from .common import _suite_result
from invart.evaluation.real_agent_conformance import run_real_agent_conformance
from invart.surfaces.adapter_profiles import list_adapter_profiles, validate_adapter_profile_truthfulness


def run_agent_adapter_contract_benchmark() -> dict[str, object]:
with tempfile.TemporaryDirectory(prefix="invart_v093_") as tmp:
root = Path(tmp)
fake = root / "fake-agent"
fake.write_text("#!/usr/bin/env python3\nimport sys\nsys.exit(0)\n", encoding="utf-8")
fake.chmod(0o755)
profiles = list_adapter_profiles()
validation = validate_adapter_profile_truthfulness(profiles)
conformance = run_real_agent_conformance(
out_dir=root / "conformance",
agents=["claude-code", "codex"],
binary_overrides={"claude-code": str(fake), "codex": str(fake)},
require_live=True,
)
by_agent = {profile["agent_id"]: profile for profile in profiles}
checks = {
"profiles_truthful": validation.get("status") == "pass",
"priority_agents_registered": {"claude-code", "codex", "hermes", "openclaw"}.issubset(by_agent),
"cloud_import_not_mediated": by_agent.get("github-copilot-cloud-agent", {}).get("supports_mediation") is False,
"claude_full_requires_evidence": {"ledger", "proof", "evidence_bundle"}.issubset(set(by_agent.get("claude-code", {}).get("required_artifacts", []))),
"fixture_conformance_passed": conformance.get("status") == "pass",
"strict_mode_records_managed_run": all(agent.get("managed_run", {}).get("status") == "pass" for agent in conformance.get("agents", [])),
}
return _suite_result(
"v0.9.3-agent-adapter-contract",
checks,
artifacts=conformance.get("artifacts", {}),
)


__all__ = ["run_agent_adapter_contract_benchmark"]
35 changes: 35 additions & 0 deletions src/invart/commands/integrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
run_official_swe_bench_lite_check,
run_swe_bench_lite_check,
)
from invart.evaluation.real_agent_conformance import export_real_agent_report_html, run_real_agent_conformance
from invart.surfaces.adapter_profiles import build_adapter_profile
from invart.surfaces.enforcement import check_enforcement, run_enforced_command, run_file_write_intercepted, rust_build_check, rust_shim_decision, rust_shim_spec
from invart.surfaces.native import install_native_integration, inventory_native_integrations, native_capability_matrix, native_conformance_report, unmanaged_agent_inventory
Expand Down Expand Up @@ -175,6 +176,40 @@ def handle_external_validation(args: argparse.Namespace) -> int:
return 0 if result.get("status") == "pass" else 1
return 2


def handle_real_agent(args: argparse.Namespace) -> int:
if args.real_agent_command == "check":
try:
binary_overrides = _parse_agent_binary_overrides(args.binary)
result = run_real_agent_conformance(
out_dir=Path(args.out_dir),
agents=args.agent or None,
binary_overrides=binary_overrides,
require_live=args.require_live,
)
except ValueError as exc:
print(str(exc), file=sys.stderr)
return 2
print(json.dumps(result, ensure_ascii=False, indent=2, sort_keys=True))
return 0 if result.get("status") == "pass" else 1
if args.real_agent_command == "report":
result = export_real_agent_report_html(Path(args.run_dir), Path(args.out))
print(json.dumps(result, ensure_ascii=False, indent=2, sort_keys=True))
return 0 if result.get("status") == "pass" else 1
return 2


def _parse_agent_binary_overrides(values: list[str]) -> dict[str, str]:
overrides: dict[str, str] = {}
for value in values:
if "=" not in value:
raise ValueError("--binary must use agent-id=/path/to/binary")
agent, path = value.split("=", 1)
if not agent or not path:
raise ValueError("--binary must use agent-id=/path/to/binary")
overrides[agent] = path
return overrides

def handle_enforce(args: argparse.Namespace) -> int:
if args.enforce_command == "check":
profile_config = resolved_profile_from_args(args)
Expand Down
17 changes: 15 additions & 2 deletions src/invart/commands/parser_integrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import argparse

from invart.evaluation.harness import SWE_BENCH_FULL_DATASET, SWE_BENCH_FULL_EXPECTED_INSTANCES, SWE_BENCH_LITE_DATASET
from invart.surfaces.adapter_profiles import adapter_profile_ids
from .common import add_profile_args
from .integrations import handle_adapter, handle_bridge, handle_coverage, handle_enforce, handle_external_validation, handle_graph, handle_harness, handle_launcher, handle_mcp, handle_mediation, handle_native, handle_supervise
from .integrations import handle_adapter, handle_bridge, handle_coverage, handle_enforce, handle_external_validation, handle_graph, handle_harness, handle_launcher, handle_mcp, handle_mediation, handle_native, handle_real_agent, handle_supervise


def register_integration_commands(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
Expand All @@ -30,7 +31,7 @@ def register_integration_commands(subparsers: argparse._SubParsersAction[argpars
adapter_package.add_argument("--ledger", required=True)
adapter_package.add_argument("--out-dir", required=True)
adapter_profile = adapter_sub.add_parser("profile", help="Inspect a hardened adapter profile.")
adapter_profile.add_argument("--kind", choices=("claude-code", "codex", "generic"), default="claude-code")
adapter_profile.add_argument("--kind", choices=adapter_profile_ids(), default="claude-code")
adapter_claude_check = adapter_sub.add_parser("claude-code-check", help="Check a real Claude Code binary environment when available.")
adapter_claude_check.add_argument("--binary", default="claude")
adapter_claude = adapter_sub.add_parser("claude-code", help="Run a command through the Claude Code wrapper/hook bridge.")
Expand Down Expand Up @@ -102,6 +103,18 @@ def register_integration_commands(subparsers: argparse._SubParsersAction[argpars
swe_full.add_argument("--expected-total-instances", type=int, default=SWE_BENCH_FULL_EXPECTED_INSTANCES)
swe_full.add_argument("--allow-subset", action="store_true", help="Mark this as a subset smoke run; it will not satisfy full external validation.")

real_agent = subparsers.add_parser("real-agent", help="Validate real or fixture-backed agent products through Invart profiles.")
real_agent.set_defaults(handler=handle_real_agent)
real_agent_sub = real_agent.add_subparsers(dest="real_agent_command", required=True)
real_agent_check = real_agent_sub.add_parser("check", help="Run agent profile and binary-shaped conformance checks.")
real_agent_check.add_argument("--agent", action="append", choices=adapter_profile_ids(), default=[])
real_agent_check.add_argument("--binary", action="append", default=[], help="Override an agent binary as agent-id=/path/to/binary.")
real_agent_check.add_argument("--require-live", action="store_true", help="Fail when requested real agent binaries are missing.")
real_agent_check.add_argument("--out-dir", default=".invart/real-agent-conformance")
real_agent_report = real_agent_sub.add_parser("report", help="Render a real-agent conformance HTML report from a run directory.")
real_agent_report.add_argument("--run-dir", required=True)
real_agent_report.add_argument("--out", required=True)

enforce = subparsers.add_parser("enforce", help="Evaluate enforcement guard decisions.")
enforce.set_defaults(handler=handle_enforce)
enforce_sub = enforce.add_subparsers(dest="enforce_command", required=True)
Expand Down
1 change: 1 addition & 0 deletions src/invart/evaluation/benchmark_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
{"suite": "v0.49-reviewer-ablation-cost", "version": "v0.49", "category": "reviewer", "optional_heavy": False, "claim_scope": "local_experiment_substrate", "evidence_level": "simulated_agent_trace"},
{"suite": "v0.50-product-control-matrix", "version": "v0.50", "category": "product-boundary", "optional_heavy": False, "claim_scope": "product_comparison", "evidence_level": "documented_capability_matrix"},
{"suite": "v0.51-pre-1.0-research-ready-gate", "version": "v0.51", "category": "release", "optional_heavy": False, "claim_scope": "research_gate", "evidence_level": "local_research_artifact_bundle"},
{"suite": "v0.9.3-agent-adapter-contract", "version": "v0.9.3", "category": "agent-adapter", "optional_heavy": False, "claim_scope": "local_agent_adapter_contract", "evidence_level": "fixture_backed_conformance"},
{"suite": "progressive-external-validation", "version": "pre-release", "category": "external-validation", "optional_heavy": False, "claim_scope": "progressive_external_validation", "evidence_level": "external_progressive_sample"},
{"suite": "real-world-agent-risk-demo", "version": "pre-release", "category": "demo", "optional_heavy": False, "claim_scope": "public_source_mapping", "evidence_level": "public_source_seed_plus_local_demo"},
{"suite": "containerized-risk-demo", "version": "pre-release", "category": "demo", "optional_heavy": False, "claim_scope": "containerized_local_demo", "evidence_level": "per_case_container_artifact_bundle"},
Expand Down
Loading
Loading