Class: Aidp::Watch::StateStore

Inherits:
Object
  • Object
show all
Defined in:
lib/aidp/watch/state_store.rb

Overview

Persists watch mode progress for each repository/issue pair. Used to avoid re-processing plan/build triggers and to retain generated plan context between runs.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(project_dir:, repository:) ⇒ StateStore

Returns a new instance of StateStore.



15
16
17
18
19
20
# File 'lib/aidp/watch/state_store.rb', line 15

def initialize(project_dir:, repository:)
  @project_dir = project_dir
  @repository = repository
  @path = File.join(project_dir, ".aidp", "watch", "#{sanitize_repository(repository)}.yml")
  ensure_directory
end

Instance Attribute Details

#pathObject (readonly)

Returns the value of attribute path.



13
14
15
# File 'lib/aidp/watch/state_store.rb', line 13

def path
  @path
end

Instance Method Details

#build_status(issue_number) ⇒ Object



56
57
58
# File 'lib/aidp/watch/state_store.rb', line 56

def build_status(issue_number)
  builds[issue_number.to_s] || {}
end

#change_request_data(pr_number) ⇒ Object



153
154
155
# File 'lib/aidp/watch/state_store.rb', line 153

def change_request_data(pr_number)
  change_requests[pr_number.to_s]
end

#change_request_processed?(pr_number) ⇒ Boolean

Change request tracking methods

Returns:

  • (Boolean)


149
150
151
# File 'lib/aidp/watch/state_store.rb', line 149

def change_request_processed?(pr_number)
  change_requests.key?(pr_number.to_s)
end

#ci_fix_completed?(pr_number) ⇒ Boolean

CI fix tracking methods

Returns:

  • (Boolean)


126
127
128
129
# File 'lib/aidp/watch/state_store.rb', line 126

def ci_fix_completed?(pr_number)
  fix_data = ci_fixes[pr_number.to_s]
  fix_data && fix_data["status"] == "completed"
end

#ci_fix_data(pr_number) ⇒ Object



131
132
133
# File 'lib/aidp/watch/state_store.rb', line 131

def ci_fix_data(pr_number)
  ci_fixes[pr_number.to_s]
end

#detection_comment_posted?(detection_key) ⇒ Boolean

Detection comment tracking methods (issue #280)

Returns:

  • (Boolean)


180
181
182
# File 'lib/aidp/watch/state_store.rb', line 180

def detection_comment_posted?(detection_key)
  detection_comments.key?(detection_key.to_s)
end

#find_build_by_pr(pr_number) ⇒ Hash?

Find the build/workstream metadata associated with a PR URL This is used to map change-request PRs back to their originating issues/worktrees.

Returns:

  • (Hash, nil)

    branch:, workstream:, pr_url:, status:



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/aidp/watch/state_store.rb', line 86

def find_build_by_pr(pr_number)
  builds.each do |issue_number, data|
    pr_url = data["pr_url"]
    next unless pr_url

    if pr_url.match?(%r{/pull/#{pr_number}\b})
      return {
        issue_number: issue_number.to_i,
        branch: data["branch"],
        workstream: data["workstream"],
        pr_url: pr_url,
        status: data["status"]
      }
    end
  end

  nil
end

#plan_data(issue_number) ⇒ Object



26
27
28
# File 'lib/aidp/watch/state_store.rb', line 26

def plan_data(issue_number)
  plans[issue_number.to_s]
end

#plan_iteration_count(issue_number) ⇒ Object



30
31
32
33
34
# File 'lib/aidp/watch/state_store.rb', line 30

def plan_iteration_count(issue_number)
  plan = plans[issue_number.to_s]
  return 0 unless plan
  plan["iteration"] || 1
end

#plan_processed?(issue_number) ⇒ Boolean

Returns:

  • (Boolean)


22
23
24
# File 'lib/aidp/watch/state_store.rb', line 22

def plan_processed?(issue_number)
  plans.key?(issue_number.to_s)
end

#record_build_status(issue_number, status:, details: {}) ⇒ Object



60
61
62
63
64
65
66
# File 'lib/aidp/watch/state_store.rb', line 60

def record_build_status(issue_number, status:, details: {})
  builds[issue_number.to_s] = {
    "status" => status,
    "updated_at" => Time.now.utc.iso8601
  }.merge(stringify_keys(details))
  save!
end

#record_change_request(pr_number, data) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/aidp/watch/state_store.rb', line 157

def record_change_request(pr_number, data)
  payload = {
    "status" => data[:status],
    "timestamp" => data[:timestamp] || Time.now.utc.iso8601,
    "changes_applied" => data[:changes_applied],
    "commits" => data[:commits],
    "reason" => data[:reason],
    "clarification_count" => data[:clarification_count],
    "verification_reasons" => data[:verification_reasons],
    "missing_items" => data[:missing_items],
    "additional_work" => data[:additional_work]
  }.compact

  change_requests[pr_number.to_s] = payload
  save!
end

#record_ci_fix(pr_number, data) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/aidp/watch/state_store.rb', line 135

def record_ci_fix(pr_number, data)
  payload = {
    "status" => data[:status],
    "timestamp" => data[:timestamp] || Time.now.utc.iso8601,
    "reason" => data[:reason],
    "root_causes" => data[:root_causes],
    "fixes_count" => data[:fixes_count]
  }.compact

  ci_fixes[pr_number.to_s] = payload
  save!
end

#record_detection_comment(detection_key, timestamp:) ⇒ Object



184
185
186
187
188
189
190
# File 'lib/aidp/watch/state_store.rb', line 184

def record_detection_comment(detection_key, timestamp:)
  detection_comments[detection_key.to_s] = {
    "timestamp" => timestamp,
    "posted_at" => Time.now.utc.iso8601
  }
  save!
end

#record_plan(issue_number, data) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/aidp/watch/state_store.rb', line 36

def record_plan(issue_number, data)
  existing_plan = plans[issue_number.to_s]
  iteration = existing_plan ? (existing_plan["iteration"] || 1) + 1 : 1

  payload = {
    "summary" => data[:summary],
    "tasks" => data[:tasks],
    "questions" => data[:questions],
    "comment_body" => data[:comment_body],
    "comment_hint" => data[:comment_hint],
    "comment_id" => data[:comment_id],
    "posted_at" => data[:posted_at] || Time.now.utc.iso8601,
    "iteration" => iteration,
    "previous_iteration_at" => existing_plan ? existing_plan["posted_at"] : nil
  }.compact

  plans[issue_number.to_s] = payload
  save!
end

#record_review(pr_number, data) ⇒ Object



114
115
116
117
118
119
120
121
122
123
# File 'lib/aidp/watch/state_store.rb', line 114

def record_review(pr_number, data)
  payload = {
    "timestamp" => data[:timestamp] || Time.now.utc.iso8601,
    "reviewers" => data[:reviewers],
    "total_findings" => data[:total_findings]
  }.compact

  reviews[pr_number.to_s] = payload
  save!
end

#reset_change_request_state(pr_number) ⇒ Object



174
175
176
177
# File 'lib/aidp/watch/state_store.rb', line 174

def reset_change_request_state(pr_number)
  change_requests.delete(pr_number.to_s)
  save!
end

#review_data(pr_number) ⇒ Object



110
111
112
# File 'lib/aidp/watch/state_store.rb', line 110

def review_data(pr_number)
  reviews[pr_number.to_s]
end

#review_processed?(pr_number) ⇒ Boolean

Review tracking methods

Returns:

  • (Boolean)


106
107
108
# File 'lib/aidp/watch/state_store.rb', line 106

def review_processed?(pr_number)
  reviews.key?(pr_number.to_s)
end

#workstream_for_issue(issue_number) ⇒ Hash?

Retrieve workstream metadata for a given issue

Returns:

  • (Hash, nil)

    branch:, workstream:, pr_url:, status:



70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/aidp/watch/state_store.rb', line 70

def workstream_for_issue(issue_number)
  data = build_status(issue_number)
  return nil if data.nil? || data.empty?

  {
    issue_number: issue_number.to_i,
    branch: data["branch"],
    workstream: data["workstream"],
    pr_url: data["pr_url"],
    status: data["status"]
  }
end