ace-assign 0.55.2 → 0.56.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: c2c5ee28861238c57ad1ed4eb0a13f5cdac6077ba56a506f416a8d9774b88b5e
4
- data.tar.gz: d8ef21c7234de7533ea22db7070f6b3148926788f00522889fd8034da6b71e6e
3
+ metadata.gz: 2735356d8b6ca0c85cd065008a49099def711664666f2e6280419b4226609c9b
4
+ data.tar.gz: 18e4449c7bf1807bab4cfa84b8d3b7ae79d206fa6fabd56835df7e2483dbd4b5
5
5
  SHA512:
6
- metadata.gz: e52bfb23af375c077647f5335709ecc501c2b22d03459675e2140db9f958424133a003d618bb2d925c3af238c1be6f627aea4aecc6d4294c50c443701eb4b236
7
- data.tar.gz: '08ae47d6ad8780bf4be67992eaed4da59a23a225fffe35f3db243dfde02d13d7ad4b480293eb964cd8139d44a9f0788cf851fc6fb638b2eebb9ce5579d5862ac'
6
+ metadata.gz: 7562bb372cd8ef57978616874139b403a78d71fc81ed35311426cba26c8fadafd1880564fc7ab7c4bae33ed2c6b0b5c2b4acc6058690fc723cf618158a637e60
7
+ data.tar.gz: 920c4a01f45060226ae96d75567d1a189c61471f8f88980f2ee986d6e1a9ecab620b13ff7c602230c7a2d44f850bf48e4a8c59770e2345ed03a56ba9f45f87a1
@@ -0,0 +1,59 @@
1
+ # work-on-task-ace-development preset
2
+ # Complete ACE framework development pipeline preset (batching, releases, demo recording, retro)
3
+
4
+ name: work-on-task-ace-development
5
+ description: Full ACE development pipeline with batching, releases, demo recording, and retrospectives
6
+
7
+ parameters:
8
+ taskrefs:
9
+ required: true
10
+ type: array
11
+ description: Task references
12
+
13
+ steps:
14
+ - name: onboard
15
+ number: "000"
16
+ workflow: wfi://onboard
17
+ instructions:
18
+ - "Load project context for the task batch: {{taskrefs}}."
19
+
20
+ - name: verify-test-suite
21
+ number: "012"
22
+ workflow: wfi://assign/verify-test-suite
23
+ instructions:
24
+ - "Verify test coverage and performance across batch tasks: {{taskrefs}}."
25
+
26
+ - name: release-minor
27
+ number: "020"
28
+ instructions:
29
+ - Release all modified packages touched by this batch.
30
+
31
+ - name: create-pr
32
+ number: "030"
33
+ workflow: wfi://github/pr/create
34
+ instructions:
35
+ - "Create a pull request summarizing batch tasks: {{taskrefs}}."
36
+
37
+ - name: review-valid-1
38
+ number: "040"
39
+ context: fork
40
+ sub_steps: [review-pr, apply-feedback, release]
41
+ instructions:
42
+ - Execute valid review cycle.
43
+
44
+ - name: record-demo
45
+ number: "145"
46
+ instructions:
47
+ - "Record a demo showing the feature implemented in this PR."
48
+
49
+ - name: mark-tasks-done
50
+ number: "155"
51
+ workflow: wfi://task/update
52
+ instructions:
53
+ - "Mark each top-level task in {{taskrefs}} as done and archive it."
54
+
55
+ - name: create-retro
56
+ number: "160"
57
+ skill: as-retro-create
58
+ instructions:
59
+ - "Create a retrospective for the batch work on: {{taskrefs}}."
@@ -0,0 +1,47 @@
1
+ # work-on-task-auto-merge preset
2
+ # Advanced authorized guarded auto-merge task delivery preset
3
+
4
+ name: work-on-task-auto-merge
5
+ description: Work on a task with PR, review cycles, and advance authorization for guarded auto-merge
6
+
7
+ parameters:
8
+ taskrefs:
9
+ required: true
10
+ type: array
11
+ description: Task references
12
+
13
+ steps:
14
+ - name: onboard
15
+ number: "000"
16
+ workflow: wfi://onboard
17
+ instructions:
18
+ - "Load project context for the task: {{taskrefs}}."
19
+
20
+ - name: create-pr
21
+ number: "030"
22
+ workflow: wfi://github/pr/create
23
+ instructions:
24
+ - "Create a pull request summarizing task: {{taskrefs}}."
25
+
26
+ - name: review-valid-1
27
+ number: "040"
28
+ context: fork
29
+ sub_steps: [review-pr, apply-feedback]
30
+ instructions:
31
+ - Execute valid review cycle and apply feedback.
32
+
33
+ - name: push-to-remote
34
+ number: "140"
35
+ instructions:
36
+ - Push changes with force-with-lease.
37
+
38
+ - name: auto-merge
39
+ number: "150"
40
+ instructions:
41
+ - "Guarded auto-merge authorized PR when checks pass."
42
+
43
+ - name: mark-tasks-done
44
+ number: "155"
45
+ workflow: wfi://task/update
46
+ instructions:
47
+ - "Mark task {{taskrefs}} done during final delivery."
@@ -0,0 +1,42 @@
1
+ # work-on-task-in-place preset
2
+ # In-place single checkout task delivery preset
3
+
4
+ name: work-on-task-in-place
5
+ description: Work on a task in the current checkout with reviewed, verified, scoped commit (no worktree, PR, or merge)
6
+
7
+ parameters:
8
+ taskrefs:
9
+ required: true
10
+ type: array
11
+ description: Task references
12
+
13
+ steps:
14
+ - name: onboard
15
+ number: "000"
16
+ workflow: wfi://onboard
17
+ instructions:
18
+ - "Load project context for the task: {{taskrefs}}."
19
+
20
+ - name: verify-test-suite
21
+ number: "012"
22
+ workflow: wfi://assign/verify-test-suite
23
+ instructions:
24
+ - "Verify test coverage for task in current checkout: {{taskrefs}}."
25
+
26
+ - name: review-valid-1
27
+ number: "040"
28
+ context: fork
29
+ sub_steps: [review-pr, apply-feedback]
30
+ instructions:
31
+ - Execute valid review cycle and apply feedback in current checkout.
32
+
33
+ - name: commit-in-place
34
+ number: "050"
35
+ instructions:
36
+ - "Create one reviewed, verified, scoped commit in the current authorized checkout."
37
+
38
+ - name: mark-tasks-done
39
+ number: "060"
40
+ workflow: wfi://task/update
41
+ instructions:
42
+ - "Mark task {{taskrefs}} done during final delivery."
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.56.0] - 2026-08-13
11
+ ### Added
12
+ - Calculate exact-head evidence for status
13
+ - Add outcome-based task presets
14
+ ### Fixed
15
+ - Resolve PR 316 findings and finalize cleanup proofs
16
+
10
17
  ## [0.55.2] - 2026-08-12
11
18
 
12
19
  ### Technical
@@ -83,6 +83,13 @@ module Ace
83
83
  end
84
84
 
85
85
  def status_to_h(assignment, state, active_steps, next_step, target:, scope_root:)
86
+ # Extract auto_merge config if present in assignment settings or preset
87
+ auto_merge = false
88
+ preset_name = Ace::Assign::Molecules::PresetInferrer.infer_from_assignment(assignment)
89
+ auto_merge = true if preset_name && preset_name.start_with?("work-on-task-auto-merge")
90
+
91
+ evidence = Ace::Assign::Molecules::EvidenceCalculator.calculate(auto_merge: auto_merge)
92
+
86
93
  payload = {
87
94
  assignment: {
88
95
  id: assignment.id,
@@ -95,6 +102,10 @@ module Ace
95
102
  }
96
103
 
97
104
  payload[:next_step] = step_to_h(next_step, effective_fork_provider: effective_fork_provider_for(next_step, scoped_fork_metadata_step(state, next_step, target.scope, scope_root))) if active_steps.empty? && next_step
105
+
106
+ # Merge exact head evidence into root payload
107
+ payload.merge!(evidence)
108
+
98
109
  payload
99
110
  end
100
111
 
@@ -33,6 +33,7 @@ require_relative "molecules/skill_assign_source_resolver"
33
33
  require_relative "molecules/fork_session_launcher"
34
34
  require_relative "molecules/tmux_control_surface_runner"
35
35
  require_relative "molecules/preset_inferrer"
36
+ require_relative "molecules/evidence_calculator"
36
37
 
37
38
  # Organisms
38
39
  require_relative "organisms/assignment_executor"
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest"
4
+ require "open3"
5
+ require "ace/support/fs"
6
+
7
+ module Ace
8
+ module Assign
9
+ module Molecules
10
+ # Computes exact-head evidence receipts and canonical decision digests for assignment delivery.
11
+ class EvidenceCalculator
12
+ def self.calculate(pr_number: nil, auto_merge: false)
13
+ new.calculate(pr_number: pr_number, auto_merge: auto_merge)
14
+ end
15
+
16
+ def calculate(pr_number: nil, auto_merge: false)
17
+ root = Ace::Support::Fs::Molecules::ProjectRootFinder.find_or_current
18
+
19
+ if pr_number.nil?
20
+ pr_output, s = Open3.capture2("ace-git", "pr", "--format", "json", chdir: root)
21
+ if s.success?
22
+ begin
23
+ require "json"
24
+ pr_data = JSON.parse(pr_output)
25
+ pr_number = pr_data["number"]
26
+ rescue StandardError
27
+ end
28
+ end
29
+ end
30
+
31
+ head, _s = Open3.capture2("git", "rev-parse", "HEAD", chdir: root)
32
+ head = head.to_s.strip
33
+
34
+ tree, _s = Open3.capture2("git", "rev-parse", "HEAD^{tree}", chdir: root)
35
+ tree = tree.to_s.strip
36
+
37
+ diff_output, _s = Open3.capture2("git", "diff", "HEAD", chdir: root)
38
+ changed_scope_digest = Digest::SHA256.hexdigest(diff_output.to_s)
39
+
40
+ review_receipt = evaluate_review_receipt(root, head)
41
+ release_receipt = evaluate_release_receipt(root, head)
42
+ feedback_state = "terminal"
43
+
44
+ merge_decision = evaluate_merge_decision(
45
+ auto_merge: auto_merge,
46
+ review_receipt: review_receipt,
47
+ release_receipt: release_receipt,
48
+ feedback_state: feedback_state
49
+ )
50
+
51
+ canonical_payload = [
52
+ pr_number || "none",
53
+ head,
54
+ tree,
55
+ changed_scope_digest,
56
+ review_receipt,
57
+ release_receipt,
58
+ feedback_state,
59
+ merge_decision
60
+ ].join(":")
61
+
62
+ decision_digest = Digest::SHA256.hexdigest(canonical_payload)
63
+
64
+ {
65
+ pr: pr_number || "none",
66
+ head: head,
67
+ tree: tree,
68
+ changed_scope_digest: changed_scope_digest,
69
+ review_receipt: review_receipt,
70
+ release_receipt: release_receipt,
71
+ feedback_state: feedback_state,
72
+ merge_decision: merge_decision,
73
+ decision_digest: decision_digest
74
+ }
75
+ end
76
+
77
+ private
78
+
79
+ def evaluate_review_receipt(root, current_head)
80
+ session_dir = File.join(root, ".ace-local", "review", "sessions")
81
+ return "missing" unless Dir.exist?(session_dir)
82
+
83
+ reviews = Dir.glob(File.join(session_dir, "*", "metadata.yml"))
84
+ return "missing" if reviews.empty?
85
+
86
+ latest = reviews.max_by { |f| File.mtime(f) }
87
+ session_dir = File.dirname(latest)
88
+
89
+ # Review must actually be executed, not just prepared
90
+ return "missing" unless File.exist?(File.join(session_dir, "report.md")) || File.exist?(File.join(session_dir, "report.json"))
91
+
92
+ begin
93
+ require "yaml"
94
+ metadata = YAML.safe_load_file(latest, permitted_classes: [Time, Date]) || {}
95
+ return "stale" unless metadata["head"] == current_head
96
+ rescue StandardError
97
+ return "missing"
98
+ end
99
+
100
+ "current"
101
+ end
102
+
103
+ def evaluate_release_receipt(root, current_head)
104
+ session_dir = File.join(root, ".ace-local", "release", "sessions")
105
+ return "missing" unless Dir.exist?(session_dir)
106
+
107
+ releases = Dir.glob(File.join(session_dir, "*", "metadata.yml"))
108
+ return "missing" if releases.empty?
109
+
110
+ latest = releases.max_by { |f| File.mtime(f) }
111
+ begin
112
+ require "yaml"
113
+ metadata = YAML.safe_load_file(latest, permitted_classes: [Time, Date]) || {}
114
+ return "stale" unless metadata["head"] == current_head
115
+ rescue StandardError
116
+ return "missing"
117
+ end
118
+
119
+ "current"
120
+ end
121
+
122
+ def evaluate_merge_decision(auto_merge:, review_receipt:, release_receipt:, feedback_state:)
123
+ return "report-only" unless auto_merge
124
+
125
+ if review_receipt == "current" && release_receipt == "current" && feedback_state == "terminal"
126
+ "authorized"
127
+ else
128
+ "approval-required"
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ace
4
4
  module Assign
5
- VERSION = "0.55.2"
5
+ VERSION = "0.56.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ace-assign
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.55.2
4
+ version: 0.56.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michal Czyz
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-08-12 00:00:00.000000000 Z
10
+ date: 2026-08-13 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: ace-support-cli
@@ -43,14 +43,14 @@ dependencies:
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '0.17'
46
+ version: '0.18'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '0.17'
53
+ version: '0.18'
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: ace-support-nav
56
56
  requirement: !ruby/object:Gem::Requirement
@@ -228,6 +228,9 @@ files:
228
228
  - ".ace-defaults/assign/presets/quick-implement.yml"
229
229
  - ".ace-defaults/assign/presets/release-only.yml"
230
230
  - ".ace-defaults/assign/presets/work-on-docs.yml"
231
+ - ".ace-defaults/assign/presets/work-on-task-ace-development.yml"
232
+ - ".ace-defaults/assign/presets/work-on-task-auto-merge.yml"
233
+ - ".ace-defaults/assign/presets/work-on-task-in-place.yml"
231
234
  - ".ace-defaults/assign/presets/work-on-task.yml"
232
235
  - ".ace-defaults/nav/protocols/skill-sources/ace-assign.yml"
233
236
  - ".ace-defaults/nav/protocols/wfi-sources/ace-assign.yml"
@@ -303,6 +306,7 @@ files:
303
306
  - lib/ace/assign/models/step.rb
304
307
  - lib/ace/assign/molecules/assignment_discoverer.rb
305
308
  - lib/ace/assign/molecules/assignment_manager.rb
309
+ - lib/ace/assign/molecules/evidence_calculator.rb
306
310
  - lib/ace/assign/molecules/fork_session_launcher.rb
307
311
  - lib/ace/assign/molecules/preset_inferrer.rb
308
312
  - lib/ace/assign/molecules/queue_scanner.rb