ace-review 0.57.0 → 0.57.1
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 +4 -4
- data/CHANGELOG.md +7 -0
- data/lib/ace/review/molecules/campaign_evidence.rb +19 -10
- data/lib/ace/review/organisms/review_manager.rb +23 -8
- data/lib/ace/review/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 865eb269684936c32eb5d91b002f98419e71b1c89155715bc486382bfa4549f3
|
|
4
|
+
data.tar.gz: 0a4bbea96d948953da5fd157c10ae83c5d6b548888663975342ae11823784195
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 70a1f4d8f88fb5d9971e961fc0918b5c0477e87a52447b877814b429775b3196c648f2d99f24b216453d30e685ea29da97cb62b93809743a8f26f484402ec622
|
|
7
|
+
data.tar.gz: 39a724d6327716608165c95de3955ae77528fd19baaf107cf035e7cdef2e99697647cc247797f9e72c8639a6535e962791fa12f70fe878a582c181e87e746b43
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.57.1] - 2026-10-02
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- A failed or incomplete provider entry no longer invalidates a campaign session's completed reviewer executions; one completed reviewer per needed scope still completes the round.
|
|
15
|
+
|
|
16
|
+
|
|
10
17
|
## [0.57.0] - 2026-10-01
|
|
11
18
|
|
|
12
19
|
### Fixed
|
|
@@ -18,6 +18,16 @@ module Ace
|
|
|
18
18
|
class CampaignEvidence
|
|
19
19
|
Contract = Atoms::CampaignContract
|
|
20
20
|
|
|
21
|
+
# One completion predicate for provider executions, shared with the
|
|
22
|
+
# extraction-inventory writer so session metadata and campaign
|
|
23
|
+
# evidence can never disagree about which reports were reviewed.
|
|
24
|
+
def self.completed_entry?(entry)
|
|
25
|
+
execution = entry["execution"] || {}
|
|
26
|
+
entry["status"] == "success" && execution["status"].to_s == "succeeded" &&
|
|
27
|
+
!execution["provider"].to_s.empty? && !execution["model"].to_s.empty? &&
|
|
28
|
+
!entry["completed_at"].to_s.empty?
|
|
29
|
+
end
|
|
30
|
+
|
|
21
31
|
def initialize(repo_root:, check_evidence: nil, review_evidence: nil, approval_evidence: nil)
|
|
22
32
|
@repo_root = File.realpath(repo_root)
|
|
23
33
|
authority = CampaignExecutionEvidence.new(repo_root: @repo_root)
|
|
@@ -57,9 +67,9 @@ module Ace
|
|
|
57
67
|
metadata = json_keys(YAML.safe_load_file(metadata_path, permitted_classes: [Time, Date, Symbol]))
|
|
58
68
|
Contract.object!(metadata, "session metadata")
|
|
59
69
|
expected = {"campaign_id" => record["id"], "contract_identity" => record["contract_identity"],
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
70
|
+
"subject" => record["subject"], "round_id" => binding["round_id"], "scope" => scope,
|
|
71
|
+
"head" => binding["head"], "base" => binding["base"],
|
|
72
|
+
"scope_identity" => binding["scope_identity"][scope]}
|
|
63
73
|
unless metadata["campaign_binding"] == expected && metadata["preset"] == expected["scope_identity"]["preset"]
|
|
64
74
|
raise Contract::Invalid, "session campaign/contract/scope/head/base identity mismatch"
|
|
65
75
|
end
|
|
@@ -83,12 +93,7 @@ module Ace
|
|
|
83
93
|
reports = []
|
|
84
94
|
entries.each do |entry|
|
|
85
95
|
Contract.object!(entry, "model execution")
|
|
86
|
-
|
|
87
|
-
complete = entry["status"] == "success" && execution["status"] == "succeeded" &&
|
|
88
|
-
!execution["provider"].to_s.empty? && !execution["model"].to_s.empty? &&
|
|
89
|
-
!entry["completed_at"].to_s.empty?
|
|
90
|
-
completed &&= complete
|
|
91
|
-
next unless complete
|
|
96
|
+
next unless self.class.completed_entry?(entry)
|
|
92
97
|
path = entry["output_file"].to_s
|
|
93
98
|
raise Contract::Invalid, "completed execution has no report" if path.empty?
|
|
94
99
|
path = File.expand_path(path, dir)
|
|
@@ -99,7 +104,7 @@ module Ace
|
|
|
99
104
|
resolved, report_ref = artifact("path" => path, "sha256" => entry["report_sha256"])
|
|
100
105
|
raise Contract::Invalid, "empty reviewer report" if File.read(resolved).strip.empty?
|
|
101
106
|
refs << report_ref
|
|
102
|
-
reports << {"artifact" => report_ref, "execution" => execution}
|
|
107
|
+
reports << {"artifact" => report_ref, "execution" => entry["execution"] || {}}
|
|
103
108
|
prompts = entry["prompt_sha256"]
|
|
104
109
|
Contract.object!(prompts, "execution prompt checksums")
|
|
105
110
|
%w[system user].each do |name|
|
|
@@ -117,6 +122,10 @@ module Ace
|
|
|
117
122
|
raise Contract::Invalid, "feedback extraction inventory or reviewed reports changed"
|
|
118
123
|
end
|
|
119
124
|
end
|
|
125
|
+
# One completed reviewer per needed scope suffices: a failed or
|
|
126
|
+
# incomplete provider entry does not count as a reviewer, but it
|
|
127
|
+
# does not invalidate the model executions that did complete.
|
|
128
|
+
completed &&= reports.any?
|
|
120
129
|
completed &&= extracted
|
|
121
130
|
proof = completed ? @review_evidence.call(input.fetch("receipt"), head: binding["head"], artifacts: refs) : nil
|
|
122
131
|
{"receipt" => input["receipt"], "execution_proof" => proof, "path" => dir.delete_prefix(@repo_root + File::SEPARATOR), "scope" => scope,
|
|
@@ -417,7 +417,8 @@ module Ace
|
|
|
417
417
|
pr_metadata: metadata, delta: delta,
|
|
418
418
|
diff_manifest: manifest.merge(scoped[:manifest]).merge(
|
|
419
419
|
exempt_files: classification[:exempt],
|
|
420
|
-
exempt_patterns: Array(config[:exempt_paths])
|
|
420
|
+
exempt_patterns: Array(config[:exempt_paths])
|
|
421
|
+
)}
|
|
421
422
|
end
|
|
422
423
|
|
|
423
424
|
scoped = apply_exempt_paths(scoped, config)
|
|
@@ -497,10 +498,10 @@ module Ace
|
|
|
497
498
|
lines << ""
|
|
498
499
|
lines << "# No-op review round"
|
|
499
500
|
lines << ""
|
|
500
|
-
if content[:noop_reason] == :empty_delta && delta
|
|
501
|
-
|
|
501
|
+
lines << if content[:noop_reason] == :empty_delta && delta
|
|
502
|
+
"Scope: delta since `#{delta[:reference_head]}` — the delta is empty; there is no change to review."
|
|
502
503
|
else
|
|
503
|
-
|
|
504
|
+
"Scope: #{content[:noop_scope] || "no-op"}."
|
|
504
505
|
end
|
|
505
506
|
lines << ""
|
|
506
507
|
lines << "Verdict: no new findings. This round is clean only if no carried-forward Critical/High finding remains unresolved."
|
|
@@ -1636,7 +1637,17 @@ module Ace
|
|
|
1636
1637
|
# completes; an absent directory cannot attest a zero-findings review.
|
|
1637
1638
|
def save_campaign_feedback_metadata(session_dir, result)
|
|
1638
1639
|
path = File.join(session_dir, "metadata.yml")
|
|
1639
|
-
metadata
|
|
1640
|
+
# Session metadata is symbol-keyed YAML; normalize before any key
|
|
1641
|
+
# reads so the completed-execution rule and the binding check see
|
|
1642
|
+
# string keys, matching the campaign evidence reader.
|
|
1643
|
+
normalize = lambda do |value|
|
|
1644
|
+
case value
|
|
1645
|
+
when Hash then value.to_h { |k, v| [k.to_s, normalize.call(v)] }
|
|
1646
|
+
when Array then value.map { |v| normalize.call(v) }
|
|
1647
|
+
else value
|
|
1648
|
+
end
|
|
1649
|
+
end
|
|
1650
|
+
metadata = normalize.call(YAML.safe_load_file(path, permitted_classes: [Time, Date, Symbol]))
|
|
1640
1651
|
return unless metadata["campaign_binding"]
|
|
1641
1652
|
extraction = {"status" => result ? "failed" : "skipped"}
|
|
1642
1653
|
if result && result[:success]
|
|
@@ -1649,9 +1660,13 @@ module Ace
|
|
|
1649
1660
|
unless result[:items_count] == ids.size && ids.uniq.size == ids.size
|
|
1650
1661
|
raise Errors::BundleProcessingError, "feedback extraction inventory is incomplete"
|
|
1651
1662
|
end
|
|
1652
|
-
entries = metadata["models"] || [YAML.safe_load_file(
|
|
1653
|
-
permitted_classes: [Time, Date, Symbol]
|
|
1654
|
-
|
|
1663
|
+
entries = metadata["models"] || [normalize.call(YAML.safe_load_file(
|
|
1664
|
+
File.join(session_dir, "llm_metadata.yml"), permitted_classes: [Time, Date, Symbol]
|
|
1665
|
+
))]
|
|
1666
|
+
# Same completed rule as the campaign evidence reader: a failed
|
|
1667
|
+
# provider that left partial output is not a reviewed report.
|
|
1668
|
+
digests = entries.select { |entry| Molecules::CampaignEvidence.completed_entry?(entry) }
|
|
1669
|
+
.map { |entry| entry["report_sha256"] }.compact
|
|
1655
1670
|
extraction = {"status" => "succeeded", "finding_ids" => ids, "report_sha256" => digests}
|
|
1656
1671
|
end
|
|
1657
1672
|
metadata["feedback_extraction"] = extraction
|
data/lib/ace/review/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ace-review
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.57.
|
|
4
|
+
version: 0.57.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michal Czyz
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-10-
|
|
10
|
+
date: 2026-10-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: ace-support-cli
|