@jphutchins/code-review 0.1.0-alpha.44 → 0.1.0-alpha.46
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.
- package/README.md +40 -28
- package/dist/index.js +320 -142
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/schema/findings.schema.json +50 -1
- package/templates/comment.eta +13 -2
- package/templates/inline.eta +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jphutchins/code-review",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.46",
|
|
4
4
|
"description": "Deterministic commenter for agentic PR review — gather, render, inline, post, adapt, extract, cost, validate, print-schema",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"type": "number",
|
|
57
57
|
"minimum": 0,
|
|
58
58
|
"maximum": 1,
|
|
59
|
-
"description": "
|
|
59
|
+
"description": "Set to 1 for a systemic problem. A structural/cross-cutting observation has no single triggering input — it is definitionally always present — so the convergence score treats a systemic problem's likelihood as 1 and never discounts it. (Required for schema symmetry with a finding's likelihood; the written value is not read by the score.)"
|
|
60
60
|
},
|
|
61
61
|
"code": {
|
|
62
62
|
"type": "string",
|
|
@@ -123,6 +123,55 @@
|
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
},
|
|
126
|
+
"convergence": {
|
|
127
|
+
"type": "object",
|
|
128
|
+
"additionalProperties": false,
|
|
129
|
+
"description": "Advisory (issue #174): the current round's convergence score, the threshold it is judged against, whether it converged, and the per-round trajectory. The review agent does NOT write this field — the pipeline computes the score deterministically from the findings (floor(severity) + headroom × confidence × likelihood, summed) and stamps it, so this JSON document is the sole source of the convergence data a decoding agent reads. `score` and `threshold` are both carried so the number is interpretable on its own (converged when score <= threshold); prior rounds are carried verbatim, so changing the threshold never rewrites a past round's score.",
|
|
130
|
+
"required": ["score", "threshold", "converged"],
|
|
131
|
+
"properties": {
|
|
132
|
+
"score": {
|
|
133
|
+
"type": "number",
|
|
134
|
+
"description": "This round's convergence score — the sum of every finding's and systemic problem's contribution, rounded to 2 decimals. Lower is closer to convergence."
|
|
135
|
+
},
|
|
136
|
+
"threshold": {
|
|
137
|
+
"type": "number",
|
|
138
|
+
"description": "The convergence tolerance in force for this round: the round is converged when score <= threshold."
|
|
139
|
+
},
|
|
140
|
+
"converged": {
|
|
141
|
+
"type": "boolean",
|
|
142
|
+
"description": "Whether this round converged (score <= threshold). Advisory only — never alters the verdict."
|
|
143
|
+
},
|
|
144
|
+
"rounds": {
|
|
145
|
+
"type": "array",
|
|
146
|
+
"description": "The convergence trajectory: one entry per completed full-review round, oldest first, this round's entry last. Each score is a historical snapshot carried verbatim.",
|
|
147
|
+
"items": {
|
|
148
|
+
"type": "object",
|
|
149
|
+
"additionalProperties": false,
|
|
150
|
+
"required": ["round"],
|
|
151
|
+
"properties": {
|
|
152
|
+
"round": {
|
|
153
|
+
"type": "integer",
|
|
154
|
+
"minimum": 1,
|
|
155
|
+
"description": "The 1-indexed completed-round number this entry represents."
|
|
156
|
+
},
|
|
157
|
+
"score": {
|
|
158
|
+
"type": "number",
|
|
159
|
+
"description": "That round's convergence score, carried verbatim from when the round completed. Absent only for a round migrated from a pre-#174 sticky, which stored no score."
|
|
160
|
+
},
|
|
161
|
+
"codes": {
|
|
162
|
+
"type": "object",
|
|
163
|
+
"additionalProperties": { "type": "integer", "minimum": 0 },
|
|
164
|
+
"description": "That round's mechanism-frequency map: finding code -> number of findings carrying it. Feeds the same-mechanism and scope-metastasis recurrence signals."
|
|
165
|
+
},
|
|
166
|
+
"sha": {
|
|
167
|
+
"type": "string",
|
|
168
|
+
"description": "The reviewed head SHA (short form) for that round, so a same-head CI retry is recognised as the same iteration rather than new recurrence evidence."
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
},
|
|
126
175
|
"findings": {
|
|
127
176
|
"type": "array",
|
|
128
177
|
"description": "Zero or more specific findings.",
|
package/templates/comment.eta
CHANGED
|
@@ -81,7 +81,7 @@ _<%= it.unanchoredCount %> finding<%= it.unanchoredCount === 1 ? '' : 's' %> bel
|
|
|
81
81
|
<% } %>
|
|
82
82
|
|
|
83
83
|
<% it.strays.forEach(function(f) { -%>
|
|
84
|
-
#### <%= it.severityEmoji(f.severity) %> (<%= f.severity %>) `<%= f.path %>:<%= f.start_line %><% if (f.start_line !== f.end_line) { %>–<%= f.end_line %><% } %>` — <%= f.title %> · confidence <%= it.formatConfidence(f.confidence) %>
|
|
84
|
+
#### <%= it.severityEmoji(f.severity) %> (<%= f.severity %>) `<%= f.path %>:<%= f.start_line %><% if (f.start_line !== f.end_line) { %>–<%= f.end_line %><% } %>` — <%= f.title %> · confidence <%= it.formatConfidence(f.confidence) %> · likelihood <%= it.formatConfidence(f.likelihood) %>
|
|
85
85
|
|
|
86
86
|
<%~ f.description %>
|
|
87
87
|
<% if (f.code && it.sameRootNotes && Object.prototype.hasOwnProperty.call(it.sameRootNotes, f.code)) { -%>
|
|
@@ -109,7 +109,7 @@ _<%= it.unanchoredCount %> finding<%= it.unanchoredCount === 1 ? '' : 's' %> bel
|
|
|
109
109
|
<% } -%>
|
|
110
110
|
|
|
111
111
|
> [!TIP]
|
|
112
|
-
> <details><summary>Reasoning (<%= it.formatConfidence(f.confidence) %> confidence)</summary>
|
|
112
|
+
> <details><summary>Reasoning (<%= it.formatConfidence(f.confidence) %> confidence · <%= it.formatConfidence(f.likelihood) %> likelihood)</summary>
|
|
113
113
|
>
|
|
114
114
|
<% f.reasoning.split("\n").forEach(function(rl) { -%>
|
|
115
115
|
> <%= rl %>
|
|
@@ -119,6 +119,17 @@ _<%= it.unanchoredCount %> finding<%= it.unanchoredCount === 1 ? '' : 's' %> bel
|
|
|
119
119
|
<% }) %>
|
|
120
120
|
<% } %>
|
|
121
121
|
|
|
122
|
+
<% if (it.suppressedNits && it.suppressedNits.length > 0) { %>
|
|
123
|
+
> [!NOTE]
|
|
124
|
+
> <details><summary>🔇 <%= it.suppressedNits.length %> nit<%= it.suppressedNits.length === 1 ? '' : 's' %> below the visibility floor (confidence × likelihood < <%= it.nitVisibilityFloor %>) — hidden</summary>
|
|
125
|
+
>
|
|
126
|
+
<% it.suppressedNits.forEach(function(n) { -%>
|
|
127
|
+
> - `<%= n.path %>:<%= n.startLine %>` — <%= n.title %><% if (n.code) { %> (`<%= n.code %>`)<% } %> _(m = <%= n.m %>)_
|
|
128
|
+
<% }) -%>
|
|
129
|
+
>
|
|
130
|
+
> </details>
|
|
131
|
+
<% } %>
|
|
132
|
+
|
|
122
133
|
<% if (it.testReport) { %>
|
|
123
134
|
---
|
|
124
135
|
|
package/templates/inline.eta
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<% if (it.findingsPointer) { -%>
|
|
2
2
|
<%~ it.findingsPointer %>
|
|
3
3
|
<% } -%>
|
|
4
|
-
<%= it.severityEmoji(it.severity) %> <%= it.severity.charAt(0).toUpperCase() + it.severity.slice(1) %>: **<%= it.title %>** · <%= it.formatConfidence(it.confidence) %> confidence
|
|
4
|
+
<%= it.severityEmoji(it.severity) %> <%= it.severity.charAt(0).toUpperCase() + it.severity.slice(1) %>: **<%= it.title %>** · <%= it.formatConfidence(it.confidence) %> confidence · <%= it.formatConfidence(it.likelihood) %> likelihood
|
|
5
5
|
|
|
6
6
|
<%~ it.description %>
|
|
7
7
|
<% if (it.sameRootNote) { -%>
|