@lsctech/polaris 0.5.6 → 0.5.8
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/dist/autoresearch/index.js +30 -1
- package/dist/autoresearch/proposal.js +5 -0
- package/dist/autoresearch/score.js +174 -2
- package/dist/autoresearch/sol-evaluation-writer.js +135 -0
- package/dist/autoresearch/sol-evidence-loader.js +40 -3
- package/dist/autoresearch/sol-evidence-normalizer.js +337 -0
- package/dist/autoresearch/sol-recommendations.js +212 -0
- package/dist/autoresearch/sol-report-renderer.js +282 -0
- package/dist/autoresearch/sol-report.js +44 -0
- package/dist/autoresearch/sol-scorecard-calculator.js +865 -0
- package/dist/autoresearch/sol-scorer.js +45 -1
- package/dist/cli/autoresearch.js +77 -0
- package/dist/cluster-state/store.js +56 -0
- package/dist/config/defaults.js +1 -0
- package/dist/config/validator.js +157 -0
- package/dist/finalize/artifact-policy.js +2 -0
- package/dist/finalize/github.js +13 -9
- package/dist/finalize/index.js +198 -4
- package/dist/finalize/linear.js +8 -4
- package/dist/finalize/steps/08-create-pr.js +2 -2
- package/dist/finalize/steps/11-update-linear.js +2 -2
- package/dist/loop/parent.js +189 -33
- package/dist/loop/worker-packet.js +75 -1
- package/dist/qc/artifacts.js +27 -0
- package/dist/qc/fixtures/repair-packets.js +170 -0
- package/dist/qc/index.js +2 -0
- package/dist/qc/orchestration.js +5 -2
- package/dist/qc/policy.js +30 -3
- package/dist/qc/providers/coderabbit.js +152 -17
- package/dist/qc/registry.js +36 -3
- package/dist/qc/repair-loop.js +458 -0
- package/dist/qc/repair-packets.js +420 -0
- package/dist/qc/runner.js +328 -37
- package/dist/qc/schemas.js +79 -1
- package/dist/types/sol-metrics.js +108 -0
- package/dist/types/sol-scorecard.js +148 -0
- package/package.json +1 -1
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SOL SmartDocs Markdown report renderer.
|
|
4
|
+
*
|
|
5
|
+
* Renders human-readable SOL evaluation reports from a run-level
|
|
6
|
+
* evaluation record, the computed scorecard set, and optional QC
|
|
7
|
+
* follow-up recommendations.
|
|
8
|
+
*
|
|
9
|
+
* Reports include:
|
|
10
|
+
* - Source references back to raw evidence
|
|
11
|
+
* - Per-subject confidence and availability
|
|
12
|
+
* - Skipped dimensions with reasons
|
|
13
|
+
* - Window / grouping metadata
|
|
14
|
+
* - Recommendation inputs for downstream routing advice
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.renderSolMarkdown = renderSolMarkdown;
|
|
18
|
+
// ──────────────────────────────────────────────
|
|
19
|
+
// Formatting helpers
|
|
20
|
+
// ──────────────────────────────────────────────
|
|
21
|
+
function fmtScore(v) {
|
|
22
|
+
return v !== null ? v.toFixed(4) : "N/A";
|
|
23
|
+
}
|
|
24
|
+
function fmtBoolean(v) {
|
|
25
|
+
if (v === null)
|
|
26
|
+
return "N/A";
|
|
27
|
+
return v ? "Yes" : "No";
|
|
28
|
+
}
|
|
29
|
+
function fmtList(items) {
|
|
30
|
+
if (!items || items.length === 0)
|
|
31
|
+
return "_None_";
|
|
32
|
+
return items.map((i) => `- ${i}`).join("\n");
|
|
33
|
+
}
|
|
34
|
+
function escapeCell(s) {
|
|
35
|
+
// Normalize line breaks so table cells remain valid Markdown.
|
|
36
|
+
return s.replace(/\r?\n/g, " ").replace(/\|/g, "\\|").trim();
|
|
37
|
+
}
|
|
38
|
+
// ──────────────────────────────────────────────
|
|
39
|
+
// Subscore table
|
|
40
|
+
// ──────────────────────────────────────────────
|
|
41
|
+
function renderSubscoreTable(scorecard) {
|
|
42
|
+
const rows = scorecard.subscores.map((s) => {
|
|
43
|
+
const value = s.score !== null ? fmtScore(s.score) : "_skipped_";
|
|
44
|
+
const reason = s.skipped_reason ? ` (${s.skipped_reason})` : "";
|
|
45
|
+
const detail = s.detail ? ` ${s.detail}` : "";
|
|
46
|
+
return `| ${s.dimension} | ${value} | ${s.confidence} | ${escapeCell(reason + detail) || "—"} |`;
|
|
47
|
+
});
|
|
48
|
+
return [
|
|
49
|
+
"| Dimension | Score | Confidence | Notes |",
|
|
50
|
+
"|---|---|---|---|",
|
|
51
|
+
...rows,
|
|
52
|
+
].join("\n");
|
|
53
|
+
}
|
|
54
|
+
// ──────────────────────────────────────────────
|
|
55
|
+
// Source references
|
|
56
|
+
// ──────────────────────────────────────────────
|
|
57
|
+
function renderSourceRefs(refs) {
|
|
58
|
+
const unique = new Map();
|
|
59
|
+
for (const ref of refs) {
|
|
60
|
+
unique.set(`${ref.kind}|${ref.path}`, ref);
|
|
61
|
+
}
|
|
62
|
+
const rows = Array.from(unique.values())
|
|
63
|
+
.sort((a, b) => a.path.localeCompare(b.path))
|
|
64
|
+
.map((r) => {
|
|
65
|
+
const status = r.available ? "available" : `missing${r.unavailable_reason ? `: ${r.unavailable_reason}` : ""}`;
|
|
66
|
+
return `| ${r.kind} | \`${r.path}\` | ${status} |`;
|
|
67
|
+
});
|
|
68
|
+
return [
|
|
69
|
+
"| Kind | Path | Status |",
|
|
70
|
+
"|---|---|---|",
|
|
71
|
+
...rows,
|
|
72
|
+
].join("\n");
|
|
73
|
+
}
|
|
74
|
+
// ──────────────────────────────────────────────
|
|
75
|
+
// Recommendation inputs
|
|
76
|
+
// ──────────────────────────────────────────────
|
|
77
|
+
function renderRecommendationInputs(scorecard) {
|
|
78
|
+
const i = scorecard.recommendation_inputs;
|
|
79
|
+
const flags = [];
|
|
80
|
+
if (i.below_threshold)
|
|
81
|
+
flags.push("below threshold");
|
|
82
|
+
if (i.over_token_budget)
|
|
83
|
+
flags.push("over token budget");
|
|
84
|
+
if (i.intervention_detected)
|
|
85
|
+
flags.push("intervention detected");
|
|
86
|
+
if (i.router_issue_detected)
|
|
87
|
+
flags.push("router issue detected");
|
|
88
|
+
if (i.qc_issue_detected)
|
|
89
|
+
flags.push("QC issue detected");
|
|
90
|
+
const cells = [
|
|
91
|
+
scorecard.subject,
|
|
92
|
+
scorecard.subject_key,
|
|
93
|
+
flags.length > 0 ? flags.join(", ") : "—",
|
|
94
|
+
i.low_scoring_dimensions.join(", ") || "—",
|
|
95
|
+
i.skipped_dimensions.join(", ") || "—",
|
|
96
|
+
];
|
|
97
|
+
return `| ${cells.map(escapeCell).join(" | ")} |`;
|
|
98
|
+
}
|
|
99
|
+
function renderRecommendationInputsHeader() {
|
|
100
|
+
return [
|
|
101
|
+
"| Subject | Key | Flags | Low dimensions | Skipped dimensions |",
|
|
102
|
+
"|---|---|---|---|---|",
|
|
103
|
+
].join("\n");
|
|
104
|
+
}
|
|
105
|
+
// ──────────────────────────────────────────────
|
|
106
|
+
// Scorecard detail section
|
|
107
|
+
// ──────────────────────────────────────────────
|
|
108
|
+
function renderScorecardDetail(scorecard) {
|
|
109
|
+
const lines = [];
|
|
110
|
+
lines.push(`### ${scorecard.subject}: ${scorecard.subject_key}`);
|
|
111
|
+
lines.push("");
|
|
112
|
+
lines.push(`- **Availability:** ${scorecard.availability}${scorecard.availability_reason ? ` — ${scorecard.availability_reason}` : ""}`);
|
|
113
|
+
lines.push(`- **Aggregate score:** ${fmtScore(scorecard.aggregate_score)} (${scorecard.aggregate_confidence})`);
|
|
114
|
+
lines.push(`- **Aggregate formula:** \`${scorecard.aggregate_formula_version}\``);
|
|
115
|
+
lines.push(`- **Window:** run_id=${scorecard.window.run_id ?? "n/a"}, cluster_id=${scorecard.window.cluster_id ?? "n/a"}, sample_count=${scorecard.window.sample_count ?? "n/a"}`);
|
|
116
|
+
const grouping = Object.entries(scorecard.grouping_keys)
|
|
117
|
+
.filter(([, v]) => v !== undefined)
|
|
118
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
119
|
+
.join(", ");
|
|
120
|
+
lines.push(`- **Grouping keys:** ${grouping || "—"}`);
|
|
121
|
+
lines.push("");
|
|
122
|
+
lines.push(renderSubscoreTable(scorecard));
|
|
123
|
+
lines.push("");
|
|
124
|
+
lines.push("**Source references**");
|
|
125
|
+
lines.push("");
|
|
126
|
+
lines.push(renderSourceRefs(scorecard.source_refs));
|
|
127
|
+
lines.push("");
|
|
128
|
+
return lines.join("\n");
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Render a complete SOL evaluation report as Markdown.
|
|
132
|
+
*/
|
|
133
|
+
function renderSolMarkdown(record, scorecardSet, qcRecommendations) {
|
|
134
|
+
const allScorecards = [
|
|
135
|
+
scorecardSet.foreman,
|
|
136
|
+
...scorecardSet.workers,
|
|
137
|
+
...scorecardSet.providers,
|
|
138
|
+
...scorecardSet.models,
|
|
139
|
+
...scorecardSet.routing,
|
|
140
|
+
];
|
|
141
|
+
const skipped = allScorecards.flatMap((s) => s.subscores
|
|
142
|
+
.filter((sub) => sub.score === null && sub.skipped_reason)
|
|
143
|
+
.map((sub) => ({ subject: s.subject, key: s.subject_key, dimension: sub.dimension, reason: sub.skipped_reason })));
|
|
144
|
+
const lines = [];
|
|
145
|
+
lines.push(`# SOL Evaluation Report: ${record.run_id}`);
|
|
146
|
+
lines.push("");
|
|
147
|
+
lines.push(`**Generated:** ${record.generated_at}`);
|
|
148
|
+
lines.push(`**Scored at:** ${record.scored_at}`);
|
|
149
|
+
lines.push(`**Cluster:** ${record.cluster_id ?? "n/a"}`);
|
|
150
|
+
lines.push("");
|
|
151
|
+
// Run-level summary
|
|
152
|
+
lines.push("## Run summary");
|
|
153
|
+
lines.push("");
|
|
154
|
+
lines.push(`| Metric | Value |`);
|
|
155
|
+
lines.push(`|---|---|`);
|
|
156
|
+
lines.push(`| Run composite score | ${fmtScore(record.report.run_composite_score)} |`);
|
|
157
|
+
lines.push(`| Foreman composite | ${fmtScore(record.report.foreman.composite_score)} (${record.report.foreman.composite_confidence}) |`);
|
|
158
|
+
lines.push(`| Worker count | ${Object.keys(record.report.workers).length} |`);
|
|
159
|
+
lines.push(`| Scorecards produced | ${allScorecards.length} |`);
|
|
160
|
+
lines.push("");
|
|
161
|
+
// Scorecard index
|
|
162
|
+
lines.push("## Scorecard index");
|
|
163
|
+
lines.push("");
|
|
164
|
+
lines.push("| Subject | Key | Aggregate | Confidence | Availability |");
|
|
165
|
+
lines.push("|---|---|---|---|---|");
|
|
166
|
+
for (const s of allScorecards) {
|
|
167
|
+
lines.push(`| ${s.subject} | ${escapeCell(s.subject_key)} | ${fmtScore(s.aggregate_score)} | ${s.aggregate_confidence} | ${s.availability} |`);
|
|
168
|
+
}
|
|
169
|
+
lines.push("");
|
|
170
|
+
// Foreman
|
|
171
|
+
lines.push("## Foreman");
|
|
172
|
+
lines.push("");
|
|
173
|
+
lines.push(renderScorecardDetail(scorecardSet.foreman));
|
|
174
|
+
// Workers
|
|
175
|
+
if (scorecardSet.workers.length > 0) {
|
|
176
|
+
lines.push("## Workers");
|
|
177
|
+
lines.push("");
|
|
178
|
+
for (const s of scorecardSet.workers) {
|
|
179
|
+
lines.push(renderScorecardDetail(s));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// Providers
|
|
183
|
+
if (scorecardSet.providers.length > 0) {
|
|
184
|
+
lines.push("## Providers");
|
|
185
|
+
lines.push("");
|
|
186
|
+
for (const s of scorecardSet.providers) {
|
|
187
|
+
lines.push(renderScorecardDetail(s));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Models
|
|
191
|
+
if (scorecardSet.models.length > 0) {
|
|
192
|
+
lines.push("## Models");
|
|
193
|
+
lines.push("");
|
|
194
|
+
for (const s of scorecardSet.models) {
|
|
195
|
+
lines.push(renderScorecardDetail(s));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// Routing
|
|
199
|
+
if (scorecardSet.routing.length > 0) {
|
|
200
|
+
lines.push("## Routing decisions");
|
|
201
|
+
lines.push("");
|
|
202
|
+
for (const s of scorecardSet.routing) {
|
|
203
|
+
lines.push(renderScorecardDetail(s));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Token efficiency
|
|
207
|
+
lines.push("## Token efficiency");
|
|
208
|
+
lines.push("");
|
|
209
|
+
const qptScorecards = allScorecards.filter((s) => s.subscores.some((sub) => sub.dimension === "quality_per_token"));
|
|
210
|
+
if (qptScorecards.length === 0) {
|
|
211
|
+
lines.push("No quality-per-token subscores were computed (token evidence may be missing).");
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
lines.push("| Subject | Key | Quality / token | Confidence |");
|
|
215
|
+
lines.push("|---|---|---|---|");
|
|
216
|
+
for (const s of qptScorecards) {
|
|
217
|
+
const qpt = s.subscores.find((sub) => sub.dimension === "quality_per_token");
|
|
218
|
+
lines.push(`| ${s.subject} | ${escapeCell(s.subject_key)} | ${fmtScore(qpt?.score ?? null)} | ${qpt?.confidence ?? "none"} |`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
lines.push("");
|
|
222
|
+
// QC outcome
|
|
223
|
+
lines.push("## QC outcome");
|
|
224
|
+
lines.push("");
|
|
225
|
+
const foremanQc = scorecardSet.foreman.subscores.find((s) => s.dimension === "qc_repair_loop");
|
|
226
|
+
if (!foremanQc) {
|
|
227
|
+
lines.push("No QC repair-loop subscore available.");
|
|
228
|
+
}
|
|
229
|
+
else if (foremanQc.score === null) {
|
|
230
|
+
lines.push(`QC repair-loop dimension skipped: ${foremanQc.skipped_reason ?? "no reason given"}.`);
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
lines.push(`QC repair-loop score: **${fmtScore(foremanQc.score)}** (${foremanQc.confidence})${foremanQc.detail ? ` — ${escapeCell(foremanQc.detail)}` : ""}`);
|
|
234
|
+
}
|
|
235
|
+
lines.push("");
|
|
236
|
+
if (qcRecommendations && qcRecommendations.recommendations.length > 0) {
|
|
237
|
+
lines.push("### QC follow-up recommendations");
|
|
238
|
+
lines.push("");
|
|
239
|
+
for (const r of qcRecommendations.recommendations) {
|
|
240
|
+
lines.push(`- **[${r.action_type}] ${r.id}** — ${escapeCell(r.proposed_action)} (${(r.confidence * 100).toFixed(1)}% confidence)`);
|
|
241
|
+
lines.push(` - Rationale: ${escapeCell(r.rationale)}`);
|
|
242
|
+
}
|
|
243
|
+
lines.push("");
|
|
244
|
+
}
|
|
245
|
+
// Recommendation inputs
|
|
246
|
+
lines.push("## Recommendation inputs");
|
|
247
|
+
lines.push("");
|
|
248
|
+
lines.push(renderRecommendationInputsHeader());
|
|
249
|
+
for (const s of allScorecards) {
|
|
250
|
+
lines.push(renderRecommendationInputs(s));
|
|
251
|
+
}
|
|
252
|
+
lines.push("");
|
|
253
|
+
// Skipped evidence
|
|
254
|
+
lines.push("## Skipped evidence");
|
|
255
|
+
lines.push("");
|
|
256
|
+
if (skipped.length === 0) {
|
|
257
|
+
lines.push("All dimensions were scored; no evidence was skipped.");
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
lines.push("| Subject | Key | Dimension | Reason |");
|
|
261
|
+
lines.push("|---|---|---|---|");
|
|
262
|
+
for (const row of skipped) {
|
|
263
|
+
lines.push(`| ${row.subject} | ${escapeCell(row.key)} | ${row.dimension} | ${escapeCell(row.reason)} |`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
lines.push("");
|
|
267
|
+
// Source references (aggregated)
|
|
268
|
+
lines.push("## Source references");
|
|
269
|
+
lines.push("");
|
|
270
|
+
lines.push(renderSourceRefs(allScorecards.flatMap((s) => s.source_refs)));
|
|
271
|
+
lines.push("");
|
|
272
|
+
const markdown = lines.join("\n");
|
|
273
|
+
return {
|
|
274
|
+
markdown,
|
|
275
|
+
summary: {
|
|
276
|
+
run_id: record.run_id,
|
|
277
|
+
aggregate_score: record.report.run_composite_score,
|
|
278
|
+
scorecard_count: allScorecards.length,
|
|
279
|
+
skipped_dimensions: skipped.length,
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.generateReport = generateReport;
|
|
13
13
|
exports.formatReportCli = formatReportCli;
|
|
14
|
+
exports.formatQcEvidence = formatQcEvidence;
|
|
14
15
|
// ──────────────────────────────────────────────
|
|
15
16
|
// Helpers
|
|
16
17
|
// ──────────────────────────────────────────────
|
|
@@ -151,3 +152,46 @@ function formatReportCli(report) {
|
|
|
151
152
|
function padRight(s, n) {
|
|
152
153
|
return s.length >= n ? s : s + " ".repeat(n - s.length);
|
|
153
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Render a human-readable summary of QC evidence and repair-loop outcomes.
|
|
157
|
+
*/
|
|
158
|
+
function formatQcEvidence(qc) {
|
|
159
|
+
const lines = [];
|
|
160
|
+
lines.push("QC Evidence Summary");
|
|
161
|
+
lines.push(` availability: ${qc.availability}`);
|
|
162
|
+
lines.push(` qc_run_count: ${qc.qc_run_count}`);
|
|
163
|
+
lines.push(` total_findings: ${qc.total_findings}`);
|
|
164
|
+
lines.push(` repaired: ${qc.repaired_findings}, open: ${qc.total_findings - qc.repaired_findings - qc.autofixed_findings - qc.waived_findings}`);
|
|
165
|
+
lines.push(` unresolved high/critical: ${qc.unresolved_high_severity}`);
|
|
166
|
+
lines.push(` blocks_delivery: ${qc.blocks_delivery}`);
|
|
167
|
+
lines.push("");
|
|
168
|
+
const providers = Object.entries(qc.provider_breakdown);
|
|
169
|
+
if (providers.length > 0) {
|
|
170
|
+
lines.push("Provider breakdown:");
|
|
171
|
+
for (const [provider, counts] of providers) {
|
|
172
|
+
lines.push(` ${provider}: total=${counts.total}, blocking=${counts.blocking}, unvalidated=${counts.unvalidated}`);
|
|
173
|
+
}
|
|
174
|
+
lines.push("");
|
|
175
|
+
}
|
|
176
|
+
if (qc.repair_loop) {
|
|
177
|
+
const loop = qc.repair_loop;
|
|
178
|
+
lines.push("Repair loop:");
|
|
179
|
+
lines.push(` status: ${loop.status}`);
|
|
180
|
+
lines.push(` rounds: ${loop.rounds_completed}/${loop.max_rounds}`);
|
|
181
|
+
lines.push(` packets: ${loop.packets_compiled} compiled, ${loop.packets_completed} completed, ${loop.packets_failed} failed`);
|
|
182
|
+
lines.push(` rerun_outcome: ${loop.rerun_outcome ?? "n/a"}`);
|
|
183
|
+
lines.push(` provider_attempts: total=${loop.provider_attempts.total}, success=${loop.provider_attempts.success}, failure=${loop.provider_attempts.failure}, fallback=${loop.provider_attempts.fallback}, skipped=${loop.provider_attempts.skipped}`);
|
|
184
|
+
lines.push(` all_providers_failed: ${loop.provider_attempts.all_providers_failed}`);
|
|
185
|
+
lines.push("");
|
|
186
|
+
}
|
|
187
|
+
if (qc.noisy_providers.length > 0) {
|
|
188
|
+
lines.push(`Noisy providers: ${qc.noisy_providers.join(", ")}`);
|
|
189
|
+
}
|
|
190
|
+
if (qc.has_repair_failures) {
|
|
191
|
+
lines.push("Repeated repair failures detected.");
|
|
192
|
+
}
|
|
193
|
+
if (qc.max_round_exhausted) {
|
|
194
|
+
lines.push("Max repair rounds exhausted.");
|
|
195
|
+
}
|
|
196
|
+
return lines.join("\n").trim() + "\n";
|
|
197
|
+
}
|