omp-worklog 0.16.1 → 0.17.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: 7acbe94c0d9ab3889a488877a4d75a94b0adfc9172b67f81620f218b854ba384
4
- data.tar.gz: dc6f213011f9e8042e1330c6d6ed408474b775f852437cb617001e463fd22bed
3
+ metadata.gz: 50fb3b897f083790dbb6414233652dda8f562c4d2cef8cd8f4da71beca65e143
4
+ data.tar.gz: 3264feb238a62462803431bc333397d655dc2f3e5a69a79126842d1e0d964946
5
5
  SHA512:
6
- metadata.gz: fc0d66c2d93b6773fa6257537498a9a44870cd539a6959a7713e0e8ebc88839a41a1e905cb4bd9c3267474fa6a02bae2472e73563885dec00dad5f48f08250de
7
- data.tar.gz: 99a9f450cae0c23de7e58af186c05dfc2ce85ae73826b86842cf766832642b09faf3908abecb0e0ac76c0cf9a956fddd636211816208fe73694e0e31db90caf7
6
+ metadata.gz: 5265237e54a305eaf0315f3768a173a43a345e8199f4ebacbb43d4f2572029496f3db21737803493b9af9cd7f6a943c586f2c30ec9734fbd95a350c12cbc2736
7
+ data.tar.gz: 961a65e2519960980b90d16434656773352cbeb2416d5abf100187461a0bad9ec8fc22a75f4895a52e454582e9b50d26ce8d0f690b6fb56084bfb72a0b91251b
data/README.md CHANGED
@@ -81,9 +81,9 @@ Type `/worklog ` to discover review, timesheet, stats, plan, and submit. Date al
81
81
 
82
82
  ### Daily Human and AI Reports and Reviewed Batches
83
83
 
84
- At the end of a workday, run `/worklog review`. It opens today's worklog inside OMP: edit each project's duration, destination, and factual note, then choose **Mark reviewed** or **Exclude entry**. When all retained entries are ready, choose **Submit to Harvest** once. No JSON editing or path copying is required. Use `/worklog review yesterday` for another day.
84
+ At the end of a workday, run `/worklog review`. It opens today's worklog inside OMP: edit each project's duration, destination, and factual note, then choose **Mark reviewed** or **Exclude entry**. A duration above the automatic candidate also requires **Edit adjustment reason**. When all retained entries are ready, choose **Submit to Harvest** and confirm the displayed snapshot. No JSON editing or path copying is required. Use `/worklog review yesterday` for another day.
85
85
 
86
- **Save and close** preserves your private draft for the next run. **Refresh evidence** rebuilds the snapshot after confirmation and retains the prior draft privately. Review does not submit anything until you explicitly choose Submit.
86
+ **Save and close** preserves your private draft, including correction reasons, for the next run. **Refresh evidence** rebuilds the snapshot after confirmation, clears corrections and review state, and retains the prior draft privately. Review does not submit anything until you approve the final confirmation.
87
87
 
88
88
  ```text
89
89
  /worklog stats 2026-10-05 2026-10-18
@@ -138,6 +138,12 @@ Version `0.14.0` is a clean identity cutover. Uninstall the retired `harvest-wor
138
138
 
139
139
  Version `0.14.3` renames the OMP slash command from `/omp-worklog` to `/worklog`; the `omp-worklog` package identity and CLI executable are unchanged.
140
140
 
141
+ ## Changes in 0.17.0
142
+
143
+ - Allow explicitly reviewed duration increases with a required private adjustment reason, without changing the automatic candidate or source evidence.
144
+ - Preserve corrections across save/resume and show candidate, reviewed duration, and rationale in the final approval.
145
+ - Keep native review, saved-batch validation, and Ruby filing consistent while retaining duplicate and uncertain-outcome protections.
146
+
141
147
  ## Changes in 0.16.1
142
148
 
143
149
  - Keep the time-off tool's numeric schema compatible with Codex requests.
@@ -19,8 +19,10 @@ module OmpWorklog
19
19
  ENTRY_KEYS = %w[
20
20
  id spentDate localProject project task candidateMilliseconds milliseconds
21
21
  humanActiveMilliseconds agentTurnMilliseconds bridgedGapMilliseconds
22
- sourceEntryIds notes reviewed reviewReasons
22
+ sourceEntryIds notes reviewed reviewReasons adjustmentReason
23
23
  ].freeze
24
+ REQUIRED_ENTRY_KEYS = (ENTRY_KEYS - ["adjustmentReason"]).freeze
25
+ MAX_SAFE_INTEGER = 9_007_199_254_740_991
24
26
 
25
27
  class InputError < StandardError
26
28
  attr_reader :code
@@ -136,7 +138,7 @@ module OmpWorklog
136
138
  end
137
139
 
138
140
  def validate_entry!(entry, from, to, seen_ids)
139
- require_hash_with_keys!(entry, ENTRY_KEYS, "invalid_entry_schema")
141
+ require_entry_keys!(entry)
140
142
  spent_date = valid_date!(entry["spentDate"], "invalid_entry_date")
141
143
  raise InputError, "entry_date_out_of_range" unless spent_date.between?(from, to)
142
144
 
@@ -149,7 +151,13 @@ module OmpWorklog
149
151
 
150
152
  candidate = positive_integer!(entry["candidateMilliseconds"], "invalid_duration")
151
153
  milliseconds = positive_integer!(entry["milliseconds"], "invalid_duration")
152
- raise InputError, "duration_exceeds_candidate" if milliseconds > candidate
154
+ adjustment_reason = entry["adjustmentReason"]
155
+ if entry.key?("adjustmentReason") && !adjustment_reason.is_a?(String)
156
+ raise InputError, "invalid_entry_schema"
157
+ end
158
+ if milliseconds > candidate && (!adjustment_reason.is_a?(String) || adjustment_reason.strip.empty?)
159
+ raise InputError, "duration_increase_requires_reason"
160
+ end
153
161
 
154
162
  nonnegative_integer!(entry["humanActiveMilliseconds"], "invalid_entry_schema")
155
163
  nonnegative_integer!(entry["agentTurnMilliseconds"], "invalid_entry_schema")
@@ -173,6 +181,13 @@ module OmpWorklog
173
181
  }
174
182
  end
175
183
 
184
+ def require_entry_keys!(entry)
185
+ unless entry.is_a?(Hash) &&
186
+ (entry.keys.sort == REQUIRED_ENTRY_KEYS.sort || entry.keys.sort == ENTRY_KEYS.sort)
187
+ raise InputError, "invalid_entry_schema"
188
+ end
189
+ end
190
+
176
191
  def require_approval!(batch)
177
192
  raise InputError, "batch_not_approved" unless @dry_run || batch[:approved]
178
193
  end
@@ -188,7 +203,7 @@ module OmpWorklog
188
203
  end
189
204
 
190
205
  def positive_integer!(value, code)
191
- raise InputError, code unless value.is_a?(Integer) && value.positive?
206
+ raise InputError, code unless value.is_a?(Integer) && value.positive? && value <= MAX_SAFE_INTEGER
192
207
 
193
208
  value
194
209
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OmpWorklog
4
- VERSION = "0.16.1"
4
+ VERSION = "0.17.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omp-worklog
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.1
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marlen Brunner