ace-review 0.56.1 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a3eb68d4c56fe426002098bd5d5dc10567ea5dcf92ba709069d526c9d8d4ca77
4
- data.tar.gz: bdaafd88e24669a1c2beb50fd16b2daf606f56b7f07d0815a36ba28deda175a3
3
+ metadata.gz: ad21edc3f01275162f0b17aaa9033413abdca90a54a89b7240305b350087ac1a
4
+ data.tar.gz: 8a516e358225b6351f05b631f0866bb51c23c7cbfdf69dfd6c19e59a764c7d29
5
5
  SHA512:
6
- metadata.gz: c1acb46ca00a76f48bd05e65f7b167e9bb395732a922bf848a8792fd342be10e85777e155eb6ba5675396a6021bd257fd9d3008dcc26a03656768f83931d9338
7
- data.tar.gz: 23c76466b28055d2c02364e711373d2743b71684b3dcb611c2523e344c430546034af289d972c3af80d590bb221f61cef8b2d977c988d334fcd620398c1467c6
6
+ metadata.gz: a22b32abda5cdfdef0c9c01a0cdeb9668aa60a98884ba93c48ea96d3c1f8ec1455fe08cbff16944afc661f2d4760a1aa644ea944b874e53ef6b5c033636d28d4
7
+ data.tar.gz: 3e65df04186e2748b7ab716555157ecb2c5e4153cb78928a8a15823717ee750f5bb346c9328f8f401f09f7570c02cf81cdade75f08159bc2aaee0afd427019c4
@@ -71,3 +71,13 @@ feedback:
71
71
 
72
72
  # Review presets - load from .ace/review/presets/*.yml
73
73
  # Individual preset files provide better organization and shareability
74
+
75
+ # Campaign persistence snapshots this policy; changing config never rewrites history.
76
+ campaign:
77
+ profiles:
78
+ delivery:
79
+ revision: delivery-v1
80
+ minimum_rounds: 3
81
+ clean_rounds: 2
82
+ required_scopes: [full]
83
+ required_checks: [tests]
data/CHANGELOG.md CHANGED
@@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.57.0] - 2026-10-01
11
+
12
+ ### Fixed
13
+
14
+ - Retain a checksummed subject identity index before publishing campaign records, preventing first-record deletion or interrupted creation from resetting history. Subject-scoped lookup isolates unrelated record corruption.
15
+ - Reject campaign-bound PR collection from a different checkout head before executing a model.
16
+ - Require an explicitly successful model entry and matching runner-recorded head before campaign completion; incomplete execution or conflicting metadata cannot count.
17
+
18
+ - Canonical GitHub repository identities reuse campaign history across trailing slashes and repository case. Local full scope rejects empty Git diffs, including distinct commits with identical trees.
19
+
20
+ - Partial High/Critical observations reset convergence across logical round IDs; a different completed round cannot reuse the preceding clean streak.
21
+ - Missing GitHub CLI/authentication produces blocked campaign JSON instead of an uncaught source exception.
22
+
23
+ ### Added
24
+
25
+ - `ace-review campaign start|status|record-round|finish`: durable campaign identity, frozen policy/contracts, linked successors and atomic checksummed history. Completed rounds and clean streak survive head changes while current acceptance requires intact evidence for all counted rounds, verified feedback, independent approval and passing checks backed by coordinator-accepted execution receipts.
26
+ - Bind existing review collection with `--campaign`, `--campaign-round` and `--campaign-scope`; incomplete/no-op/failed attempts do not advance round counters. Replay is idempotent and conflicting writes fail.
27
+ - Independent approval binds an accepted ordinary review receipt to the exact head, producer/reviewer and reports; caller approval JSON or collection evidence cannot grant acceptance. Retained approvals remain authority-backed across head drift.
28
+ - Packaged campaign usage and assignment receipt integration through the existing coordinator authority.
29
+
30
+ ### Fixed
31
+
32
+ - Existing campaign status and finish use their own checksummed successor marker, so unrelated corrupt records cannot block them. Publish supersession before the successor record so an interrupted publication remains blocked.
33
+
34
+ ### Technical
35
+
36
+ - Approval rejection coverage first validates accepted session evidence and then asserts rejection at approval authority, preventing stale checksums from making the negative control pass early.
37
+
10
38
  ## [0.56.1] - 2026-09-29
11
39
 
12
40
  ### Fixed
data/README.md CHANGED
@@ -56,3 +56,7 @@ ace-test-e2e ace-review
56
56
 
57
57
  ---
58
58
  [Getting Started](docs/getting-started.md) | [Usage Guide](docs/usage.md) | [Handbook - Skills, Agents, Templates](docs/handbook.md) | Part of [ACE](https://github.com/cs3b/ace)
59
+
60
+ ### Durable review campaigns
61
+
62
+ Use `ace-review campaign start|status|record-round|finish` to retain review history independently of current-head evidence. See [campaign usage](docs/campaigns.md) for frozen contracts/policy, pinned scopes, restart/replay and assignment receipt consumption. Existing review and feedback commands remain primary operations.
data/docs/campaigns.md ADDED
@@ -0,0 +1,154 @@
1
+ # Durable review campaigns
2
+
3
+ A campaign preserves verified review history across commits, squash, rebase and process restarts. Its search counters describe completed rounds; current acceptance also requires current-head evidence, passing required checks and an independent reviewer approval. Campaign commands execute no models, commits, merges, publications or deployments.
4
+
5
+ ## Start and inspect
6
+
7
+ Use a frozen requirements document containing behavioral requirements only. Do not supply mutable task status, implementation plans or completion reports as requirements. Place input artifacts under `.ace-local/` so they do not change the candidate worktree.
8
+
9
+ ```sh
10
+ mkdir -p .ace-local/campaign-input
11
+ # Run inside the candidate repository. This writes a local discovery identity.
12
+ python3 - <<'PY'
13
+ import json, pathlib
14
+ root = pathlib.Path.cwd().resolve()
15
+ out = root / '.ace-local/campaign-input'
16
+ (out / 'subject.json').write_text(json.dumps({
17
+ 'repository': 'local:' + str(root), 'local_candidate_id': 'candidate-a'
18
+ }))
19
+ (out / 'requirements.md').write_text('Reject invalid input and preserve accepted history.\n')
20
+ PY
21
+ ace-review campaign start --subject .ace-local/campaign-input/subject.json \
22
+ --contract .ace-local/campaign-input/requirements.md --profile delivery --dry-run
23
+ ace-review campaign start --subject .ace-local/campaign-input/subject.json \
24
+ --contract .ace-local/campaign-input/requirements.md --profile delivery
25
+ ace-review campaign status CAMPAIGN_ID --format json
26
+ ```
27
+
28
+ Expected: dry-run emits `dry_run: true` without creating campaign state. GitHub repository case and a trailing slash normalize to the same repository/PR identity and reuse the same findings/history. Start emits a `campaign_id`, the requirements content digest and a policy snapshot. Initial status has zero completed rounds and `accepted: false`. In this repository use `bin/ace-review` for every invocation.
29
+
30
+ For an existing GitHub subject use `{"repository":"https://github.com/owner/repo","pr":"owner/repo#42"}`. The identity format is provider-neutral; collection currently supports the existing local and GitHub sources. An unavailable forge adapter is an explicit error. Local repository identity is `local:` followed by its real checkout path; different local candidates use different `local_candidate_id` values.
31
+
32
+ ## Pin and collect a round
33
+
34
+ Before collection, record a pin with empty sessions and dispositions. `attempt_id` identifies one immutable recording submission; `round_id` identifies the logical round. Use a new attempt ID for partial progress and completion. Required scopes must equal the frozen policy scopes. Each scope identity pins the review preset and explicit subject selectors before collection. Collection must use those exact selectors. The local `full` scope requires only the exact pinned diff selector; file subsets use explicit module scope IDs in the frozen policy. PR `full` also requires the collector’s complete verified diff inventory with no filtered or exempted files and no delta reference; module presets and delta collection use explicit module or delta scope IDs. Both collection and recording validate the manifest.
35
+
36
+ ```json
37
+ {
38
+ "attempt_id": "pin-r1",
39
+ "round_id": "r1",
40
+ "head": "EXACT_REVIEWED_HEAD_SHA",
41
+ "base": "EXACT_REVIEWED_BASE_SHA",
42
+ "required_scopes": ["full"],
43
+ "scope_identity": {"full": {"preset":"code-valid","subjects":["diff:EXACT_BASE_SHA..EXACT_HEAD_SHA"]}},
44
+ "sessions": [],
45
+ "dispositions": []
46
+ }
47
+ ```
48
+
49
+ Replace the SHA placeholders with exact Git revisions. For local campaigns, the latest explicit round pin defines the current base; changing that pin invalidates older-base evidence while preserving history. Both revisions must exist as Git commits. A local `full` scope must contain a nonempty Git diff; equal revisions or distinct commits with identical trees are rejected at pinning, collection and acceptance. For PR scopes pin `subjects: ["pr:owner/repo#42"]`; PR collection uses the fetched PR head/base. The reserved `full` scope always covers the whole PR. For delta collection, freeze an explicit `delta` scope in the policy; that scope additionally pins `delta_reference_head` to an exact SHA in its scope identity and collects with `--delta SHA`; a delta cannot satisfy a scope pinned without that reference. Candidate code must be committed before campaign collection or acceptance. Untracked artifacts under the ACE-private `.ace-local/` directory do not dirty the candidate, even without a gitignore entry. Tracked changes there and tracked or untracked source changes elsewhere still block collection and acceptance.
50
+
51
+ ```sh
52
+ ace-review campaign record-round CAMPAIGN_ID --input .ace-local/campaign-input/pin.json
53
+ ace-review --preset code-valid --subject diff:EXACT_BASE_SHA..EXACT_HEAD_SHA --auto-execute \
54
+ --campaign CAMPAIGN_ID --campaign-round r1 --campaign-scope full
55
+ ```
56
+
57
+ Expected: the pin reports `recorded_complete: false`, then the existing review runner writes its ordinary session artifacts with the pinned campaign/contract/scope/head/base binding. Other review invocations, repeated model/subject/evidence flags and feedback commands retain their normal behavior. A zero-model no-op, failed/incomplete report, or skipped/failed feedback extraction cannot complete a campaign round. Do not use `--no-feedback` for campaign collection. The runner records a successful extraction inventory, including explicit zero findings; deleting a listed finding invalidates the session. Local head/base values must name available Git commits.
58
+
59
+ Verify findings with `ace-review-feedback verify --valid|--invalid --research ... --session SESSION`, and resolve repairs with `ace-review-feedback resolve --resolution ... --session SESSION`. Every feedback item must have substantive verification research; resolved items also need a resolution.
60
+
61
+ ## Record coverage and dispositions
62
+
63
+ Submit a new attempt ID with all reports needed for the round. Metadata, reports and prompts must retain their execution checksums. An artifact reference always has repository-relative `path` and SHA-256 of the exact file bytes.
64
+
65
+ ```json
66
+ {
67
+ "attempt_id": "complete-r1",
68
+ "round_id": "r1",
69
+ "head": "EXACT_REVIEWED_HEAD_SHA",
70
+ "base": "EXACT_REVIEWED_BASE_SHA",
71
+ "required_scopes": ["full"],
72
+ "scope_identity": {"full": {"preset":"code-valid","subjects":["diff:EXACT_BASE_SHA..EXACT_HEAD_SHA"]}},
73
+ "sessions": [{"scope":"full","metadata":{
74
+ "path":".ace-local/review/sessions/review-SESSION/metadata.yml",
75
+ "sha256":"METADATA_SHA256"
76
+ }, "receipt":{"attempt_id":"ACCEPTED_COLLECTION_ATTEMPT_ID","digest":"ACCEPTED_COLLECTION_RECEIPT_SHA256"}}],
77
+ "dispositions": [{
78
+ "source_id":".ace-local/review/sessions/review-SESSION#FEEDBACK_ID",
79
+ "reason":"Verified claim against the requirements and regression test."
80
+ }]
81
+ }
82
+ ```
83
+
84
+ Each completed session requires an immutable execution receipt already accepted by ace-assign's coordinator. Collect the real review under an existing managed assignment attempt, then submit a normal succeeded receipt with `operation: "review-collect"`, a passed `review-execution` check, live head and checksummed artifacts covering `metadata.yml`, the report files, both prompts, and `llm_metadata.yml` for a single-model execution. This attests successful collection, including a report containing blocking findings; it does not approve the candidate. Record its accepted attempt ID/digest in the session's `receipt` field. Collection metadata alone, a check receipt, or a receipt from a different session cannot count as executed review. Campaign commands read this proof through `ace-assign attempt evidence --kind review-collection`; they never create execution attempts or a second journal. The trusted coordinator must validate actual execution and its artifacts before accepting the collection receipt. Acceptance is that coordinator's attestation: the local operator or OS-enforced service verifies the operation and accepts its attributable outcome; worker claims cannot accept themselves. Campaigns consume this existing trust boundary and do not add a process executor or independent process-attestation system. Evidence queries read accepted receipts from the managed immutable Git journal; editable attempt caches and unmanaged histories cannot certify execution.
85
+
86
+ Use `dispositions: []` for a session with no findings. Every source finding needs exactly one disposition. Findings from incomplete or unaccepted sessions cannot change campaign assessments. A completed individual module session may supply verified findings while other required scopes are still incomplete. Source status derives the disposition: pending/skip stays open, done is resolved, invalid is invalid. A confirmed High/Critical makes the round non-clean even if already resolved. The same rule applies to a High/Critical observed during partial coverage. It resets the clean streak immediately even if already resolved and that logical round never completes; completing a different round cannot preserve the old streak. Two subsequent clean rounds are still required by the default policy. Earlier findings remain open when absent from later reports. A confirmed High/Critical in a later partial round invalidates the earlier approval even if resolved; complete that round and collect the required subsequent clean reviews.
87
+
88
+ `finding_id` optionally links an assessment to an existing canonical finding. Reopening requires `disposition: "reopened"` and a new verified source occurrence; terminal feedback files are never forced back to pending. Corrections are appended to campaign history. Recording preserves exact verified finding bytes under `campaigns/evidence/`, so normal pending-to-done/invalid feedback updates do not erase earlier assessments. To resolve an earlier open finding, update and verify its original feedback item, then include its existing `source_id` and a reason in the next submission alongside current sessions. Its terminal source is revalidated and snapshotted; the old report does not count as current scope coverage, and the resolution alone is not a newly observed High/Critical. A later change to a canonical finding previously confirmed High/Critical still invalidates an earlier approval, including invalidation or a severity reduction, until a completed current round covers the candidate; an empty or partial submission cannot make that old approval acceptable. A submission cannot assign two source findings to the same canonical finding ID; submit one verified assessment per canonical claim. A linked successor contract retains predecessor findings for explicit disposition.
89
+
90
+ ```sh
91
+ ace-review campaign record-round CAMPAIGN_ID --input .ace-local/campaign-input/complete.json
92
+ ace-review campaign status CAMPAIGN_ID --format json
93
+ ```
94
+
95
+ Expected: complete coverage increments `completed_rounds` once. Identical replay returns `replayed: true`; conflicting content for the same attempt or completed round fails nonzero. Partial scope coverage persists as an attempt without incrementing completed or clean counters. Reusing a report from an already counted round is rejected. Provider calls, report files, recording attempts and completed rounds are separate counters.
96
+
97
+ ## Current approval and finish
98
+
99
+ Delivery defaults are three completed rounds and two consecutive rounds without confirmed High/Critical. The default scope is `full` and required check name is `tests`. Configure `campaign.profiles.delivery` in `.ace/review/config.yml`, or supply `start --policy FILE` with exactly `revision`, `minimum_rounds`, `clean_rounds`, `required_scopes`, `required_checks`. Explicit false/null or otherwise malformed policy files fail instead of selecting defaults. The campaign freezes that revision and policy. R1 does not implement discovery profiles, round caps, automatic retries or escalation.
100
+
101
+ The final round may reference an explicit approval artifact with `approval: {"path": ..., "sha256": ...}`. An approval binds an independently approved executed review already accepted by the assignment coordinator. Caller-written approval JSON alone cannot supply the verdict. It must contain:
102
+
103
+ ```json
104
+ {
105
+ "producer":"IMPLEMENTER_ACTOR",
106
+ "reviewer":"ACTUAL_EXECUTED_REVIEWER_MODEL",
107
+ "verdict":"approved",
108
+ "head":"EXACT_REVIEWED_HEAD_SHA",
109
+ "base":"EXACT_REVIEWED_BASE_SHA",
110
+ "contract_identity":"FROZEN_CONTRACT_SHA256",
111
+ "required_scopes":["full"],
112
+ "reports":[{"path":"SESSION/review-report-MODEL.md","sha256":"REPORT_SHA256"}],
113
+ "receipt":{"attempt_id":"ACCEPTED_REVIEW_APPROVAL_ATTEMPT_ID","digest":"ACCEPTED_RECEIPT_SHA256"},
114
+ "checks":[{"name":"tests","verdict":"passed","receipt":{
115
+ "attempt_id":"ACCEPTED_CHECK_ATTEMPT_ID","digest":"ACCEPTED_RECEIPT_SHA256"
116
+ }}]
117
+ }
118
+ ```
119
+
120
+ The approval `receipt` refers to an ordinary managed `operation: "review"` receipt with an executed `review.verdict: "approved"`, the same exact head, producer/reviewer actors and checksummed report artifacts. Submit that attributable outcome through the existing coordinator after the independent reviewer actually approves. Do not include a campaign result in this source receipt; campaign consumption happens afterward. The read-only `attempt evidence --kind review-approval` boundary revalidates its accepted authority. A collection receipt certifies execution even when its report rejects the candidate; it cannot certify approval. Every retained approval remains authority-backed across head changes through explicit historical validation.
121
+
122
+ Producer and reviewer must differ. Reviewer identity must match the actual completed execution model in the referenced session; approvals must cover every required scope. Required checks refer to a succeeded execution receipt already accepted by the ace-assign coordinator. The receipt operation must match the check: `tests` requires `test`; other explicit check names require the same operation name. An unrelated operation claiming a passed tests field is rejected. Run the check under an existing managed assignment attempt and submit its attributable result, current head, check outcomes and checksummed artifacts through `ace-assign attempt finish`. Use the accepted attempt ID and receipt digest here. A self-authored check JSON file is insufficient. Campaign recording and acceptance consult the read-only `ace-assign attempt evidence --attempt ID --receipt-digest DIGEST --format json --kind check --check-name tests` boundary, which revalidates current head and source artifacts against accepted history. Retain `ace-assign` alongside `ace-review` for this qjl evidence capability; unavailable authority blocks acceptance explicitly. Campaign commands never run the check for you or create a second execution journal. Authenticated producer/reviewer attribution and execution acceptance remain owned by ace-assign.
123
+
124
+ ```sh
125
+ ace-review campaign finish CAMPAIGN_ID --format json
126
+ ```
127
+
128
+ Expected: exit zero and `accepted: true` only with convergence, no unresolved High/Critical, intact current-head/base evidence, independent approval and all passing required checks. Missing GitHub CLI or authentication blocks PR start/status/finish with a parseable source-unavailable reason. Otherwise finish emits parseable JSON with `accepted: false` and reasons and exits nonzero. Save the JSON result using your calling process's file API; the CLI does not publish it.
129
+
130
+ ## Consume through an assignment
131
+
132
+ Submit a normal succeeded review receipt through `ace-assign attempt finish`. Add this optional reference and include the identical result artifact in the receipt's verified `artifacts` array:
133
+
134
+ ```json
135
+ {"campaign":{"id":"CAMPAIGN_ID","result":{
136
+ "path":".ace-local/campaign-input/result.json","sha256":"RESULT_SHA256"
137
+ }}}
138
+ ```
139
+
140
+ The receipt retains ordinary attempt/assignment/project/scope binding, producer, current head, reviewer approval and executed checks. Its producer/reviewer actors must match the campaign assessment. The trusted coordinator rechecks live campaign state and rejects stale, blocked, mismatched or dry-run results. Accepting evidence records a separate journal commit without moving the candidate branch.
141
+
142
+ ## Restart, contract changes and failures
143
+
144
+ Campaign authority lives in `.ace-local/review/campaigns/`; retain this directory and source evidence across process/context restarts. Records are serialized with a lock and replaced atomically with checksums. Every retained completed session, including earlier rounds and partial coverage, must keep its immutable accepted review-collection authority. Historical reads use `ace-assign attempt evidence --kind review-collection --historical-head EXACT_RECORDED_HEAD` to validate that receipt and its artifacts. This read-only mode cannot certify current checks; check-purpose proofs always require the live head. Losing/corrupting evidence from any retained counted round or assessment makes it unavailable; historical counters remain diagnostic and do not manufacture acceptance. These records are durable local artifacts, not a second assignment execution journal.
145
+
146
+ Start with changed requirements and `--reason "Requirement X changed"` to create a linked successor; `--predecessor ID` selects it explicitly. Same active subject/requirements/policy starts reuse one campaign, including concurrently. Requirements A → B → A create a new A successor of B; the superseded first A remains history. Restore missing active records rather than creating an orphan campaign that forgets them. Conflicting policy for an existing contract fails rather than rewriting history. A successor durably supersedes its predecessor: status keeps predecessor history and exposes `active_contract: false` and `superseded_by`, while collection, new recordings and acceptance are blocked. Old results cannot pass the assignment receipt verifier.
147
+
148
+ The checksummed `.identity-index.json` retains each subject’s campaign IDs and is published before a new campaign record. A missing indexed record blocks that subject’s start/reuse, including deletion of its first record; restore the retained record to recover. Missing or corrupt indexes and unregistered records fail closed; no automatic reconstruction discards history. Subject lookup reads only its indexed records, so unrelated missing/corrupt campaign records do not block reuse. Retain the index together with the records. Existing campaign `status` and `finish` inspect their own checksummed record and successor marker.
149
+
150
+ `status` is read-only and exits successfully for known blocked/stale state. Unknown/corrupt campaigns fail. `start`, `record-round` and `finish` support `--dry-run` without state writes. JSON remains parseable with `--quiet`/`--verbose`; `--format text` supplies compact presentation. No force option bypasses evidence.
151
+
152
+ Retain the campaign evidence snapshots as well as original review sessions. Missing retained report: restore the exact retained artifact at its recorded path; collecting a new round does not erase the missing source requirement. Incomplete scope: use a new attempt ID for the same pinned round with complete coverage. Changed head/base: preserve history and collect current evidence. Invalid/mixed identity: correct the explicit input; no source is silently redirected. Conflicting replay: keep the accepted submission and use a new logical round for new evidence.
153
+
154
+ Campaign-bound GitHub collection requires checkout `HEAD` to equal the fetched PR head before model execution. Check out the candidate first; the accepted execution receipt and runner metadata then identify the same reviewed code. Ordinary unbound PR collection continues to support a different checkout head.
@@ -0,0 +1,32 @@
1
+ ---
2
+ description: Showcase ace-review presets, diff review, PR review, and feedback
3
+ tags:
4
+ - ace-review
5
+ - docs
6
+ - getting-started
7
+ settings:
8
+ font_size: 12
9
+ width: 960
10
+ height: 540
11
+ format: gif
12
+ env:
13
+ PROJECT_ROOT_PATH: /home/mc/ace-t.5nx
14
+ scenes:
15
+ - name: Switch to project root
16
+ commands:
17
+ - type: cd $PROJECT_ROOT_PATH && clear
18
+ sleep: 1s
19
+ - name: List available presets
20
+ commands:
21
+ - type: ace-review --list-presets
22
+ sleep: 3s
23
+ - name: Review branch diff with preset
24
+ commands:
25
+ - type: ace-review --preset code-fit --subject diff:origin/main..HEAD --dry-run
26
+ sleep: 3s
27
+ - name: Run a review
28
+ commands:
29
+ - type: ace-review --preset code-fit --subject "files:ace-retro/**/*.rb"
30
+ sleep: 10s
31
+ teardown:
32
+ - cleanup