rails-informant 0.1.0 → 0.1.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/lib/generators/rails_informant/skill/templates/SKILL.md +7 -1
- data/lib/rails_informant/engine.rb +4 -9
- data/lib/rails_informant/mcp/server.rb +9 -6
- data/lib/rails_informant/mcp/tools/get_informant_status.rb +5 -1
- data/lib/rails_informant/mcp/tools/mark_fix_pending.rb +1 -1
- data/lib/rails_informant/mcp/tools/verify_pending_fixes.rb +90 -0
- data/lib/rails_informant/mcp.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0efea7b3e9161f6868f46fa2996fc426ad132eb3cb0b5a814963447472ff83ff
|
|
4
|
+
data.tar.gz: 2b73bff8211ebd79de66056c91321ec3a79989c8f38f415235d2f9e0d49fdc4c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f6b50ea3c2c678ae9239a89846bba3759bdfb57c08e2b12724c43125529a08892a6a45d9d5c1e9cfb5d72eac77dbd18534b075f4043a23cdcac184b7f1bde9c4
|
|
7
|
+
data.tar.gz: 8e9c3fcfea6562d5d925b6824a27d50da602c2a72c3f87e673aa74a0922ad9025e15da4f35df7adcefd88dc095c5c336f3c1601c9350290627d80989c957db9e
|
|
@@ -27,7 +27,13 @@ When implementing a fix:
|
|
|
27
27
|
5. Verify test passes
|
|
28
28
|
6. Commit + open draft PR
|
|
29
29
|
7. Call `mark_fix_pending` with fix_sha, original_sha, and fix_pr_url
|
|
30
|
-
|
|
30
|
+
|
|
31
|
+
## Verify Deployed Fixes
|
|
32
|
+
|
|
33
|
+
After a deploy, run `verify_pending_fixes` to confirm fix_pending errors are resolved.
|
|
34
|
+
This checks if each fix_sha is an ancestor of the deployed code using git locally.
|
|
35
|
+
Check `get_informant_status` — if `deploy_sha` has changed since you last checked, a deploy has occurred.
|
|
36
|
+
Ensure the local repo is up to date (`git fetch`) before running verification.
|
|
31
37
|
|
|
32
38
|
## Important Notes
|
|
33
39
|
|
|
@@ -39,19 +39,14 @@ module RailsInformant
|
|
|
39
39
|
)
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
initializer "rails_informant.
|
|
42
|
+
initializer "rails_informant.log_pending_fixes" do
|
|
43
43
|
config.after_initialize do
|
|
44
44
|
next unless RailsInformant.server_mode?
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
next
|
|
46
|
+
count = RailsInformant::ErrorGroup.where(status: "fix_pending").count
|
|
47
|
+
next if count.zero?
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
RailsInformant::ErrorGroup
|
|
51
|
-
.where(status: "fix_pending")
|
|
52
|
-
.where.not(original_sha: current_sha)
|
|
53
|
-
.in_batches(of: 100)
|
|
54
|
-
.update_all(status: "resolved", resolved_at: now, fix_deployed_at: now, updated_at: now)
|
|
49
|
+
Rails.logger.info "[Informant] #{count} error(s) awaiting fix verification"
|
|
55
50
|
rescue ActiveRecord::StatementInvalid
|
|
56
51
|
# Table may not exist yet during initial migration
|
|
57
52
|
end
|
|
@@ -6,10 +6,11 @@ module RailsInformant
|
|
|
6
6
|
|
|
7
7
|
## Triage Workflow
|
|
8
8
|
1. Check `get_informant_status` for overview counts by status
|
|
9
|
-
2.
|
|
10
|
-
3.
|
|
11
|
-
4.
|
|
12
|
-
5.
|
|
9
|
+
2. If fix_pending count > 0 in the status response, run `verify_pending_fixes` to check deployed fixes
|
|
10
|
+
3. List unresolved errors with `list_errors(status: "unresolved")`
|
|
11
|
+
4. Pick the highest-impact error
|
|
12
|
+
5. Investigate with `get_error` (includes up to 10 recent occurrences)
|
|
13
|
+
6. For errors with many occurrences, use `list_occurrences` to paginate through all of them
|
|
13
14
|
|
|
14
15
|
## Assessment Criteria
|
|
15
16
|
Prioritize by: frequency (occurrence count), impact (affects critical paths),
|
|
@@ -23,7 +24,8 @@ module RailsInformant
|
|
|
23
24
|
duplicate → unresolved
|
|
24
25
|
|
|
25
26
|
## Resolution Strategies
|
|
26
|
-
- Clear fix available → write fix, call `mark_fix_pending` with commit SHAs
|
|
27
|
+
- Clear fix available → write fix, call `mark_fix_pending` with commit SHAs. After deploy, run `verify_pending_fixes` to confirm and resolve.
|
|
28
|
+
- Pending fixes deployed → `verify_pending_fixes` checks git ancestry and resolves verified fixes
|
|
27
29
|
- Not actionable → `annotate_error` with reason, then `ignore_error`
|
|
28
30
|
- Same root cause as another → `mark_duplicate` with target ID
|
|
29
31
|
- Needs context → `annotate_error` with findings
|
|
@@ -60,7 +62,8 @@ module RailsInformant
|
|
|
60
62
|
Tools::MarkDuplicate,
|
|
61
63
|
Tools::MarkFixPending,
|
|
62
64
|
Tools::ReopenError,
|
|
63
|
-
Tools::ResolveError
|
|
65
|
+
Tools::ResolveError,
|
|
66
|
+
Tools::VerifyPendingFixes
|
|
64
67
|
].freeze
|
|
65
68
|
|
|
66
69
|
def self.build(config)
|
|
@@ -13,7 +13,11 @@ module RailsInformant
|
|
|
13
13
|
|
|
14
14
|
def self.call(server_context:, environment: nil)
|
|
15
15
|
with_client(server_context:, environment:) do |client|
|
|
16
|
-
|
|
16
|
+
result = client.status
|
|
17
|
+
if result["fix_pending_count"]&.positive?
|
|
18
|
+
result["hint"] = "#{result["fix_pending_count"]} error(s) awaiting fix verification. Run verify_pending_fixes to check if their fixes have been deployed."
|
|
19
|
+
end
|
|
20
|
+
text_response result
|
|
17
21
|
end
|
|
18
22
|
end
|
|
19
23
|
end
|
|
@@ -3,7 +3,7 @@ module RailsInformant
|
|
|
3
3
|
module Tools
|
|
4
4
|
class MarkFixPending < BaseTool
|
|
5
5
|
tool_name "mark_fix_pending"
|
|
6
|
-
description "Mark as fix_pending (unresolved → fix_pending) with the fix commit SHA, original SHA, and optional PR URL.
|
|
6
|
+
description "Mark as fix_pending (unresolved → fix_pending) with the fix commit SHA, original SHA, and optional PR URL. After deploy, run verify_pending_fixes to confirm and resolve. Valid from: unresolved."
|
|
7
7
|
input_schema(
|
|
8
8
|
properties: {
|
|
9
9
|
environment: { type: "string", description: "Target environment (defaults to first configured)" },
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
module RailsInformant
|
|
2
|
+
module Mcp
|
|
3
|
+
module Tools
|
|
4
|
+
class VerifyPendingFixes < BaseTool
|
|
5
|
+
tool_name "verify_pending_fixes"
|
|
6
|
+
description "Verify fix_pending errors by checking if their fix_sha is an ancestor of the deployed code. Resolves verified fixes. Requires git locally. Results reflect local git state — run git fetch first to ensure accuracy."
|
|
7
|
+
input_schema(
|
|
8
|
+
properties: {
|
|
9
|
+
auto_resolve: { type: "boolean", description: "Resolve verified fixes automatically (default: true)" },
|
|
10
|
+
environment: { type: "string", description: "Target environment (defaults to first configured)" },
|
|
11
|
+
target_ref: { type: "string", description: "Git ref to verify against (default: deploy_sha from status API)" }
|
|
12
|
+
}
|
|
13
|
+
)
|
|
14
|
+
annotations(read_only_hint: false, destructive_hint: false, idempotent_hint: true)
|
|
15
|
+
|
|
16
|
+
MAX_PAGES = 10
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
def call(server_context:, auto_resolve: true, environment: nil, target_ref: nil)
|
|
20
|
+
with_client(server_context:, environment:) do |client|
|
|
21
|
+
return error_response "git is not available. Run this tool from a machine with git installed." unless git_available?
|
|
22
|
+
|
|
23
|
+
ref = target_ref || fetch_deploy_sha(client)
|
|
24
|
+
return error_response "No deploy SHA available. Pass target_ref explicitly." unless ref
|
|
25
|
+
return error_response "Invalid target_ref" if ref.start_with?("-")
|
|
26
|
+
|
|
27
|
+
errors = fetch_all_fix_pending client
|
|
28
|
+
return text_response("message" => "No fix_pending errors found", "verified" => [], "pending" => []) if errors.empty?
|
|
29
|
+
|
|
30
|
+
verified = []
|
|
31
|
+
pending = []
|
|
32
|
+
|
|
33
|
+
errors.each do |error|
|
|
34
|
+
fix_sha = error["fix_sha"]
|
|
35
|
+
if fix_sha && ancestor?(fix_sha, ref)
|
|
36
|
+
verified << error
|
|
37
|
+
else
|
|
38
|
+
pending << error
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
if auto_resolve && verified.any?
|
|
43
|
+
verified.each { |error| client.update_error error["id"], status: "resolved" }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
text_response(
|
|
47
|
+
"message" => "Verified #{verified.size} of #{errors.size} fix_pending error(s)",
|
|
48
|
+
"deploy_sha" => ref,
|
|
49
|
+
"resolved_count" => auto_resolve ? verified.size : 0,
|
|
50
|
+
"verified" => verified.map { summarize it },
|
|
51
|
+
"pending" => pending.map { summarize it }
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def ancestor?(fix_sha, target_ref)
|
|
59
|
+
system "git", "merge-base", "--is-ancestor", fix_sha, target_ref, out: File::NULL, err: File::NULL
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def fetch_all_fix_pending(client)
|
|
63
|
+
errors = []
|
|
64
|
+
page = 1
|
|
65
|
+
loop do
|
|
66
|
+
result = client.list_errors status: "fix_pending", page:, per_page: 100
|
|
67
|
+
errors.concat result["data"]
|
|
68
|
+
break unless result.dig("meta", "has_more")
|
|
69
|
+
page += 1
|
|
70
|
+
break if page > MAX_PAGES
|
|
71
|
+
end
|
|
72
|
+
errors
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def fetch_deploy_sha(client)
|
|
76
|
+
client.status&.dig("deploy_sha")
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def git_available?
|
|
80
|
+
system "git", "rev-parse", "--git-dir", out: File::NULL, err: File::NULL
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def summarize(error)
|
|
84
|
+
{ "id" => error["id"], "error_class" => error["error_class"], "message" => error["message"], "fix_sha" => error["fix_sha"], "fix_pr_url" => error["fix_pr_url"] }
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
data/lib/rails_informant/mcp.rb
CHANGED
|
@@ -19,4 +19,5 @@ require_relative "mcp/tools/mark_duplicate"
|
|
|
19
19
|
require_relative "mcp/tools/mark_fix_pending"
|
|
20
20
|
require_relative "mcp/tools/reopen_error"
|
|
21
21
|
require_relative "mcp/tools/resolve_error"
|
|
22
|
+
require_relative "mcp/tools/verify_pending_fixes"
|
|
22
23
|
require_relative "mcp/server"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails-informant
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel López Prat
|
|
@@ -159,6 +159,7 @@ files:
|
|
|
159
159
|
- lib/rails_informant/mcp/tools/mark_fix_pending.rb
|
|
160
160
|
- lib/rails_informant/mcp/tools/reopen_error.rb
|
|
161
161
|
- lib/rails_informant/mcp/tools/resolve_error.rb
|
|
162
|
+
- lib/rails_informant/mcp/tools/verify_pending_fixes.rb
|
|
162
163
|
- lib/rails_informant/middleware/error_capture.rb
|
|
163
164
|
- lib/rails_informant/middleware/rescued_exception_interceptor.rb
|
|
164
165
|
- lib/rails_informant/notifiers/notification_policy.rb
|