ace-hitl 0.25.0 → 0.25.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f9115490bffe274fbc591fc0c0c3efb826c70fe549b17e7d57b5928e298ffe23
4
- data.tar.gz: e14fa6ef9c4251fcad792f2c8cbdd362fe642b9c66dc7060fa621e6785f65d0a
3
+ metadata.gz: a02c62f4939a60bf11cecc65e359987ef263fe520191bf42ac806326eb9cebaf
4
+ data.tar.gz: 998d00803a4a9b88e3f92bdd506288e4ca536339dd9cb328a9d79568be689e79
5
5
  SHA512:
6
- metadata.gz: b8f52aef4b90d868a62e1966523282ea1a74eabe20930034736e1a73a941c701df4c4580297659ea8c5255dc45676cf3f37b466c934faa5ce7d71e10cc2d4a5f
7
- data.tar.gz: 202ca6825f02dcaec4da9fce88aaeef2ca66c33f98ef6cf51daa6585ec552dc7eeff8cfb3556ad35881aa0ccfa3cb13fc7653b68077a0ffbfcddbbf5b6e6f686
6
+ metadata.gz: c5745f91860ee25c500cecdbaff63efec395c4588cd064fa0df225a8844abdadf4a3f8ab10ba8fde9a83817212a3924a799b2909b79ea244a68c4d7df2dbb46f
7
+ data.tar.gz: 64a33f6d3de1f218fd60702a0c37072b95688fef66c853b8c8c02f1936108ff156e79f8761a70bb4e9b6c263288de77a7b2478469ce494be53d7198351adad7e
data/CHANGELOG.md CHANGED
@@ -5,6 +5,14 @@ All notable changes to `ace-hitl` will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [0.25.1] - 2026-11-10
11
+
12
+ ### Fixed
13
+
14
+ - Share strict recipient selection between observation and report acceptance; preserve observation owner identity across worktrees.
15
+
8
16
  ## [0.25.0] - 2026-10-30
9
17
 
10
18
  ### Fixed (review rounds 3/3b + re-review R2)
@@ -8,12 +8,13 @@ module Ace
8
8
  class Observe < Ace::Support::Cli::Command
9
9
  desc "Read bounded semantic event revisions without private message text"
10
10
  option :scope, type: :string, default: "current", desc: "current or all linked worktrees"
11
+ option :in, type: :string, default: "next", desc: "next for live events; all to verify archived publications"
11
12
  option :owner, type: :string, desc: "Configured recipient owning incoming events"
12
13
  option :limit, type: :integer, default: 500, desc: "Maximum event count (1..2000)"
13
14
  def call(**options)
14
15
  scope = options[:scope] || "current"
15
16
  raise Ace::Support::Cli::Error, "invalid scope" unless %w[current all].include?(scope)
16
- puts JSON.generate(Molecules::EventObservation.new.call(scope: scope, limit: options[:limit] || 500, owner: options[:owner]))
17
+ puts JSON.generate(Molecules::EventObservation.new.call(scope: scope, limit: options[:limit] || 500, owner: options[:owner], in_folder: options[:in] || "next"))
17
18
  rescue ArgumentError => e
18
19
  raise Ace::Support::Cli::Error, e.message
19
20
  end
@@ -13,12 +13,8 @@ module Ace
13
13
  @manager = manager
14
14
  end
15
15
 
16
- def call(scope: "current", limit: 500, owner: nil)
17
- raise ArgumentError, "invalid observation limit" unless (1..2000).cover?(limit)
18
- events = @manager.list(in_folder: "next", scope: scope, limit: limit, strict: true)
19
- raise ArgumentError, "observation exceeds configured event budget" if events.size > limit
20
- address = owner && Molecules::HitlAddressResolver.new(config: @manager.config).resolve(owner)
21
- events = events.select { |event| incoming?(event, address) } if address
16
+ def call(scope: "current", limit: 500, owner: nil, in_folder: "next")
17
+ events = incoming_events(scope: scope, limit: limit, owner: owner, in_folder: in_folder)
22
18
  rows = events.map do |event|
23
19
  semantic = [event.id, event.type, event.status, event.result, event.kind,
24
20
  event.title, event.content, event.answer, event.questions,
@@ -32,6 +28,18 @@ module Ace
32
28
  {"schema" => "ace.hitl.observation/v1", "events" => rows.sort_by { |row| row["key"] }}
33
29
  end
34
30
 
31
+ # Shared read boundary for observation and report consumers. Preserve
32
+ # strict enumeration and recipient ownership in both paths.
33
+ def incoming_events(scope: "current", limit: 500, owner: nil, in_folder: "next")
34
+ raise ArgumentError, "invalid observation limit" unless (1..2000).cover?(limit)
35
+ raise ArgumentError, "invalid observation folder" unless %w[next all].include?(in_folder)
36
+ events = @manager.list(in_folder: in_folder, scope: scope, limit: limit, strict: true)
37
+ raise ArgumentError, "observation exceeds configured event budget" if events.size > limit
38
+ address = owner && Molecules::HitlAddressResolver.new(config: @manager.config).resolve(owner)
39
+ events = events.select { |event| incoming?(event, address) } if address
40
+ events
41
+ end
42
+
35
43
  private
36
44
 
37
45
  # Questions created locally are outbound until actually answered. A
@@ -115,7 +115,7 @@ module Ace
115
115
 
116
116
  def list(status: nil, kind: nil, type: nil, delivery: nil, in_folder: "next", tags: [], scope: nil, limit: nil, strict: false)
117
117
  effective_scope = @scope_resolver.effective_scope(scope)
118
- scan_results = scan_results_for_scope(effective_scope, in_folder: in_folder)
118
+ scan_results = scan_results_for_scope(effective_scope, in_folder: in_folder, strict: strict)
119
119
  raise ArgumentError, "observation exceeds configured event budget" if limit && scan_results.size > limit
120
120
  events = load_events(scan_results)
121
121
  raise ArgumentError, "incomplete HITL observation" if strict && events.size != scan_results.size
@@ -838,11 +838,12 @@ module Ace
838
838
  }
839
839
  end
840
840
 
841
- private def scan_results_for_scope(scope, in_folder:)
841
+ private def scan_results_for_scope(scope, in_folder:, strict:)
842
842
  total = 0
843
843
  folder_counts = Hash.new(0)
844
844
 
845
845
  results = hitl_roots_for_scope(scope).uniq.flat_map do |hitl_root|
846
+ verify_observation_root!(hitl_root) if strict
846
847
  scanner = Molecules::HitlScanner.new(hitl_root)
847
848
  scoped_results = scanner.scan_in_folder(in_folder)
848
849
  total += scanner.last_scan_total.to_i
@@ -855,6 +856,16 @@ module Ace
855
856
  results
856
857
  end
857
858
 
859
+ private def verify_observation_root!(path)
860
+ return if File.stat(path).directory?
861
+
862
+ raise Errno::ENOTDIR, path
863
+ rescue Errno::ENOENT
864
+ # A worktree can legitimately have no events and no store yet.
865
+ # A dangling symlink, however, explicitly points at a lost source.
866
+ raise if File.symlink?(path)
867
+ end
868
+
858
869
  private def load_events(scan_results)
859
870
  scan_results.filter_map { |scan_result| load_event(scan_result) }
860
871
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ace
4
4
  module Hitl
5
- VERSION = "0.25.0"
5
+ VERSION = "0.25.1"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ace-hitl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.25.0
4
+ version: 0.25.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michal Czyz
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-10-30 00:00:00.000000000 Z
10
+ date: 2026-11-10 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: ace-hitl-contract