diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index a58210b..fa4f82d 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "loop-engineer", - "version": "0.10.0", + "version": "0.11.0", "description": "Design, launch, verify, repair, and improve agent loops. A Claude-Code-native architect+operator for long-running, verifiable, self-improving agentic-coding systems.", "author": { "name": "Sollan Systems", diff --git a/CHANGELOG.md b/CHANGELOG.md index fc7f38f..de191c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,53 @@ All notable changes to `loop-engineer` are documented here. `WORKFLOW.md` and `README.md` are reworded to describe the mechanism; the 0.3.4 history is left intact. +## 0.11.0 — 2026-07-26 + +**Verifier identity, and evidence that is load-bearing.** Two slices of the +tamper-evident-provenance program ship together, because neither was cut on its own. + +*Verifier identity and independence (PR #94).* evidence@1 records now carry +`verified_by.code_digest` and `verified_by.policy_digest` — the runner hashes the +verifier it actually executed and the goalpost it was held to. `loop doctor` +reports `self_verified_evidence` when a record declares that its producer also +verified it, making the independence rule of `reference/safety-and-approvals.md` §5 +a machine check rather than prose. Verify bundles record the visible/held-out +criterion partition. + +*Evidence wiring (PR #102).* A verified dispatch binds its evidence digests into +the hash chain at append time, using the existing `artifact_hashes` envelope field +— no new event type and still one append per dispatch. The bundle is also written +to a content-addressed object store whose location is derived from the digest, so +a third-party reader finds the original bytes from `record["sha256"]` alone and a +swapped bundle no longer destroys the evidence. `loop doctor` hash-verifies every +discovered record, re-hashes what the chain bound, and compares a record's +`policy_digest` against the live `TASKS.json` goalpost. Five new issue codes: +`evidence_chain_mismatch`, `missing_bound_evidence`, `policy_digest_mismatch`, +`unverified_evidence_terminal`, `bound_evidence_escape`. + +**Behavioural flag — `Succeeded` can now mean more.** The opt-in +`completion_policy.mode: all_required_verified_evidence` requires every cited +evidence entry to be a workspace-relative record that hash-verifies, **attests a +pass**, is chain-bound wherever a store exists, and agrees with the live goalpost. +The default `all_required` is unchanged and every record written before this +release still validates. The canonical green-marker rule now lives in +`loop.evidence.verify_bundle_is_green` and is shared object-for-object with +`scripts/metrics.py`, so a bundle cannot read RED to the FCR gate and GREEN to the +completion gate. + +**Known limitations, stated rather than discovered.** Binding makes tampering +detectable against an anchor, not impossible: without `--expect-chain-head` a +worker who can rewrite `.loop/` can rewrite the chain too, and a contract with no +event store cannot chain-bind at all. Deleting `.loop/events.db` after a run leaves +plain `loop doctor` quiet — the `missing_event_store` tripwire only fires on +leftover `-wal`/`-shm` residue — so the external anchor is the control that holds. +Four upgrade notes in `reference/repo-os-contract.md` §17 name the behaviour that +can turn a previously-clean contract red: `policy_digest_mismatch` is not opt-in +and has no first-class re-baseline affordance; the `completion_policy` enum +widening is forward-incompatible as a hard error against an older kernel; `os.link` +now runs once per dispatch; and a bound artifact above the 64 MiB read cap fails +doctor with no configuration knob. + ## 0.10.0 — 2026-07-25 **The hash-linked event chain.** Every `loop-engineer/event@1` row now carries diff --git a/README.md b/README.md index 51100ca..10745d7 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![CI](https://github.com/SollanSystems/loop-engineer/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/SollanSystems/loop-engineer/actions/workflows/ci.yml) [![Python 3.10–3.12](https://img.shields.io/badge/python-3.10%E2%80%933.12-blue)](https://www.python.org/downloads/) [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE) -[![Release](https://img.shields.io/badge/release-0.10.0-blue)](https://github.com/SollanSystems/loop-engineer/tags) +[![Release](https://img.shields.io/badge/release-0.11.0-blue)](https://github.com/SollanSystems/loop-engineer/tags) Long-running agents commit **false completion**. After context compaction they forget what "done" meant, optimize to the visible test, patch in circles, and @@ -340,7 +340,7 @@ present. Recipe: **CI** — one workflow step validates the contract and publishes a scorecard: ```yaml -- uses: SollanSystems/loop-engineer@v0.10.0 +- uses: SollanSystems/loop-engineer@v0.11.0 with: path: "." ``` @@ -433,8 +433,8 @@ doctor` and the contract's own `verify-*` scripts). ## Status -- Version: `0.10.0` -- Release tag: `v0.10.0` (PyPI publish trigger; plugin tags through 0.6.0 used `loop-engineer--v`) +- Version: `0.11.0` +- Release tag: `v0.11.0` (PyPI publish trigger; plugin tags through 0.6.0 used `loop-engineer--v`) - License: MIT - Primary interface: Claude Code plugin - Portable core: Python CLI + JSON schemas diff --git a/pyproject.toml b/pyproject.toml index fcbc7a6..8c60228 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "loop-engineer" -version = "0.10.0" +version = "0.11.0" description = "Portable Loop Contract Core: validate and inspect repo-native operating contracts for agent loops." readme = "README.md" requires-python = ">=3.10" diff --git a/scripts/test_docs_version.py b/scripts/test_docs_version.py index 870cec1..40f662c 100644 --- a/scripts/test_docs_version.py +++ b/scripts/test_docs_version.py @@ -17,7 +17,7 @@ def test_readme_has_no_stale_seven_skills(): def test_plugin_version_is_0_10_0(): plugin = json.loads(_read(".claude-plugin/plugin.json")) - assert plugin["version"] == "0.10.0" + assert plugin["version"] == "0.11.0" def test_pyproject_version_matches_plugin(): @@ -39,7 +39,7 @@ def test_readme_version_surfaces_match_plugin_version(): def test_changelog_has_current_and_historical_entries(): changelog = _read("CHANGELOG.md") - assert "## 0.10.0" in changelog + assert "## 0.11.0" in changelog assert "## 0.9.0" in changelog assert "## 0.8.0" in changelog assert "## 0.7.0" in changelog