mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-17 05:08:59 +00:00
fix(quality): clear the cycle's 11 net-new ESLint errors + make validate-release-green suppressions-aware
- executor-kiro/save-call-log/call-logs-correlation tests: replace 15 'as any' casts with typed shapes (net-new no-explicit-any errors from #6213/#6216); prune the now-empty suppression entries so the frozen baseline stays exact - github-skills + usage/call-logs routes: raw toLowerCase().includes() search replaced by matchesSearch() (no-restricted-syntax — Turkish-safe search, behavior covered by tests/unit/call-logs-correlation-substring.test.ts and tests/unit/github-collector.test.ts) - validate-release-green.mjs: run ESLint with --suppressions-location (match the npm run lint contract — frozen debt is not a release red) and raise the lint timeout 15->30min (a full pass takes ~14min alone; the 15min ceiling expired under concurrent suite load and surfaced as 'could not parse eslint json')
This commit is contained in:
parent
509fd5425c
commit
fecf888fd9
7 changed files with 173 additions and 53 deletions
|
|
@ -1392,11 +1392,6 @@
|
|||
"count": 1
|
||||
}
|
||||
},
|
||||
"tests/unit/executor-kiro.test.ts": {
|
||||
"@typescript-eslint/no-explicit-any": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"tests/unit/executor-nlpcloud.test.ts": {
|
||||
"@typescript-eslint/no-explicit-any": {
|
||||
"count": 2
|
||||
|
|
@ -2002,11 +1997,6 @@
|
|||
"count": 9
|
||||
}
|
||||
},
|
||||
"tests/unit/save-call-log-persistence.test.ts": {
|
||||
"@typescript-eslint/no-explicit-any": {
|
||||
"count": 7
|
||||
}
|
||||
},
|
||||
"tests/unit/schema-coercion.test.ts": {
|
||||
"@typescript-eslint/no-explicit-any": {
|
||||
"count": 12
|
||||
|
|
|
|||
|
|
@ -53,7 +53,9 @@ const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|||
/** Read the committed ratchet baseline value for a metric (null if unknown). */
|
||||
export function baselineValue(metric, root = ROOT) {
|
||||
try {
|
||||
const raw = JSON.parse(readFileSync(join(root, "config/quality/quality-baseline.json"), "utf8"));
|
||||
const raw = JSON.parse(
|
||||
readFileSync(join(root, "config/quality/quality-baseline.json"), "utf8")
|
||||
);
|
||||
const metrics = raw.metrics || raw;
|
||||
const v = metrics?.[metric]?.value;
|
||||
return typeof v === "number" ? v : null;
|
||||
|
|
@ -178,7 +180,13 @@ function main() {
|
|||
const hardCmd = (id, label, cmd, cmdArgs, opts) => {
|
||||
announce(label);
|
||||
const { code, out } = run(cmd, cmdArgs, opts);
|
||||
record({ id, label, kind: "hard", ok: code === 0, detail: code === 0 ? "pass" : firstFailureLine(out) });
|
||||
record({
|
||||
id,
|
||||
label,
|
||||
kind: "hard",
|
||||
ok: code === 0,
|
||||
detail: code === 0 ? "pass" : firstFailureLine(out),
|
||||
});
|
||||
};
|
||||
|
||||
// A ratchet command (check:complexity, check:dead-code, …) exits 1 ONLY on a
|
||||
|
|
@ -189,7 +197,13 @@ function main() {
|
|||
const driftCmd = (id, label, cmd, cmdArgs, okDetail = "within baseline", opts) => {
|
||||
announce(label);
|
||||
const { code, out } = run(cmd, cmdArgs, opts);
|
||||
record({ id, label, kind: "drift", ok: code === 0, detail: code === 0 ? okDetail : firstFailureLine(out) });
|
||||
record({
|
||||
id,
|
||||
label,
|
||||
kind: "drift",
|
||||
ok: code === 0,
|
||||
detail: code === 0 ? okDetail : firstFailureLine(out),
|
||||
});
|
||||
};
|
||||
|
||||
process.stderr.write("🔎 Release-green validation (current working tree)\n\n");
|
||||
|
|
@ -198,14 +212,41 @@ function main() {
|
|||
|
||||
// ESLint: ONE pass → errors (hard) + warnings (drift)
|
||||
{
|
||||
announce("ESLint (errors + warnings — ~3-6min)");
|
||||
const { out } = run("npx", ["eslint", ".", "--format", "json"], { timeout: 15 * 60 * 1000 });
|
||||
announce("ESLint (errors + warnings — ~5-15min)");
|
||||
// Suppressions-aware, matching `npm run lint` (Pacote 4 no-new-warnings): the frozen
|
||||
// pre-existing debt in config/quality/eslint-suppressions.json must not count as
|
||||
// errors here — only NET-NEW violations are release reds. Timeout raised: a full
|
||||
// repo pass takes ~14min alone and this pre-flight often runs alongside test suites.
|
||||
const { out } = run(
|
||||
"npx",
|
||||
[
|
||||
"eslint",
|
||||
".",
|
||||
"--format",
|
||||
"json",
|
||||
"--suppressions-location",
|
||||
"config/quality/eslint-suppressions.json",
|
||||
],
|
||||
{ timeout: 30 * 60 * 1000 }
|
||||
);
|
||||
const parsed = parseEslintJson(out);
|
||||
if (!parsed) {
|
||||
record({ id: "lint", label: "ESLint", kind: "hard", ok: false, detail: "could not parse eslint json" });
|
||||
record({
|
||||
id: "lint",
|
||||
label: "ESLint",
|
||||
kind: "hard",
|
||||
ok: false,
|
||||
detail: "could not parse eslint json",
|
||||
});
|
||||
} else {
|
||||
const { errors, warnings } = eslintCounts(parsed);
|
||||
record({ id: "lint-errors", label: "ESLint errors", kind: "hard", ok: errors === 0, detail: `${errors} error(s)` });
|
||||
record({
|
||||
id: "lint-errors",
|
||||
label: "ESLint errors",
|
||||
kind: "hard",
|
||||
ok: errors === 0,
|
||||
detail: `${errors} error(s)`,
|
||||
});
|
||||
const base = baselineValue("eslintWarnings");
|
||||
const over = isDrift(warnings, base);
|
||||
record({
|
||||
|
|
@ -283,9 +324,20 @@ function main() {
|
|||
driftCmd("complexity", "Cyclomatic complexity (ratchet)", npmCmd, ["run", "check:complexity"]);
|
||||
driftCmd("dead-code", "Dead-code (ratchet)", npmCmd, ["run", "check:dead-code"]);
|
||||
driftCmd("type-coverage", "Type coverage (ratchet)", npmCmd, ["run", "check:type-coverage"]);
|
||||
driftCmd("compression-budget", "Compression budget (ratchet)", npmCmd, ["run", "check:compression-budget"]);
|
||||
driftCmd("openapi-coverage", "OpenAPI route coverage (ratchet)", npmCmd, ["run", "check:openapi-coverage"]);
|
||||
driftCmd("workflow-lint", "Workflow lint (zizmor ratchet)", npmCmd, ["run", "check:workflows", "--", "--ratchet"]);
|
||||
driftCmd("compression-budget", "Compression budget (ratchet)", npmCmd, [
|
||||
"run",
|
||||
"check:compression-budget",
|
||||
]);
|
||||
driftCmd("openapi-coverage", "OpenAPI route coverage (ratchet)", npmCmd, [
|
||||
"run",
|
||||
"check:openapi-coverage",
|
||||
]);
|
||||
driftCmd("workflow-lint", "Workflow lint (zizmor ratchet)", npmCmd, [
|
||||
"run",
|
||||
"check:workflows",
|
||||
"--",
|
||||
"--ratchet",
|
||||
]);
|
||||
driftCmd("codeql-ratchet", "CodeQL alerts (ratchet)", npmCmd, ["run", "check:codeql-ratchet"]);
|
||||
|
||||
// Docs sync + fabricated-docs (strict) is a real-defect gate (invented env vars /
|
||||
|
|
@ -298,15 +350,35 @@ function main() {
|
|||
// with 15 such reds). They run SILENTLY for many minutes; the announce line above + these
|
||||
// hard ceilings keep a long-but-healthy run from being mistaken for a hang (the ceiling also
|
||||
// converts a genuine DB-handle hang into a visible failure instead of an infinite block).
|
||||
hardCmd("unit", "Unit tests (full suite, CI concurrency — runs ~20-35min silently)", npmCmd, ["run", "test:unit:ci"], { timeout: 45 * 60 * 1000 });
|
||||
hardCmd("vitest", "Vitest (MCP / autoCombo / cache — ~3-8min)", npmCmd, ["run", "test:vitest"], { timeout: 15 * 60 * 1000 });
|
||||
hardCmd(
|
||||
"unit",
|
||||
"Unit tests (full suite, CI concurrency — runs ~20-35min silently)",
|
||||
npmCmd,
|
||||
["run", "test:unit:ci"],
|
||||
{ timeout: 45 * 60 * 1000 }
|
||||
);
|
||||
hardCmd(
|
||||
"vitest",
|
||||
"Vitest (MCP / autoCombo / cache — ~3-8min)",
|
||||
npmCmd,
|
||||
["run", "test:vitest"],
|
||||
{ timeout: 15 * 60 * 1000 }
|
||||
);
|
||||
// Integration tests run ONLY on the release PR full CI (PR→main), so an assertion
|
||||
// regression here (e.g. a contributor flipping a Codex fingerprint key order) is
|
||||
// invisible until release — run them in the pre-flight as a HARD gate.
|
||||
hardCmd("integration", "Integration tests (~3-10min)", npmCmd, ["run", "test:integration"], { timeout: 20 * 60 * 1000 });
|
||||
hardCmd("integration", "Integration tests (~3-10min)", npmCmd, ["run", "test:integration"], {
|
||||
timeout: 20 * 60 * 1000,
|
||||
});
|
||||
}
|
||||
if (WITH_BUILD) {
|
||||
hardCmd("pack-artifact", "Package artifact (npm pack policy)", npmCmd, ["run", "check:pack-artifact"], { timeout: 20 * 60 * 1000 });
|
||||
hardCmd(
|
||||
"pack-artifact",
|
||||
"Package artifact (npm pack policy)",
|
||||
npmCmd,
|
||||
["run", "check:pack-artifact"],
|
||||
{ timeout: 20 * 60 * 1000 }
|
||||
);
|
||||
}
|
||||
|
||||
const { releaseGreen, hardFailures, drift } = computeVerdict(results);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
*/
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { searchGitHubSkills } from "@/lib/skills/githubCollector";
|
||||
import { matchesSearch } from "@/shared/utils/turkishText";
|
||||
import { buildErrorBody, sanitizeErrorMessage } from "@omniroute/open-sse/utils/error";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
|
@ -31,9 +32,8 @@ export async function GET(request: NextRequest) {
|
|||
let filtered = repos;
|
||||
if (minScore > 0) filtered = filtered.filter((r) => r.score >= minScore);
|
||||
if (query) {
|
||||
const q = query.toLowerCase();
|
||||
filtered = filtered.filter(
|
||||
(r) => r.fullName.toLowerCase().includes(q) || r.description.toLowerCase().includes(q)
|
||||
(r) => matchesSearch(r.fullName, query) || matchesSearch(r.description, query)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
|
|||
import { getCallLogs } from "@/lib/usageDb";
|
||||
import { getCompletedDetails, getPendingById } from "@/lib/usage/usageHistory";
|
||||
import { getProviderConnections } from "@/lib/localDb";
|
||||
import { matchesSearch } from "@/shared/utils/turkishText";
|
||||
|
||||
type CallLogListRowsInput = {
|
||||
logs: any[];
|
||||
|
|
@ -147,10 +148,8 @@ export async function GET(request: Request) {
|
|||
// (active + completed) that don't match — getCallLogs already filters
|
||||
// the DB rows but activeEntries/completedEntries bypass it.
|
||||
if (filter.correlationId) {
|
||||
const cid = filter.correlationId.toLowerCase();
|
||||
return NextResponse.json(
|
||||
rows.filter((r: any) => (r.correlationId || "").toLowerCase().includes(cid))
|
||||
);
|
||||
const cid = filter.correlationId;
|
||||
return NextResponse.json(rows.filter((r: any) => matchesSearch(r.correlationId || "", cid)));
|
||||
}
|
||||
|
||||
return NextResponse.json(rows);
|
||||
|
|
|
|||
|
|
@ -22,15 +22,54 @@ function seedLogs() {
|
|||
db.prepare(
|
||||
`INSERT OR REPLACE INTO call_logs (id, timestamp, method, path, status, model, provider, account, duration, tokens_in, tokens_out, correlation_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
||||
).run("log-1", now, "POST", "/v1/chat/completions", 200, "gpt-4", "openai", "acc1", 100, 10, 20, "abc123-def456-ghi789");
|
||||
).run(
|
||||
"log-1",
|
||||
now,
|
||||
"POST",
|
||||
"/v1/chat/completions",
|
||||
200,
|
||||
"gpt-4",
|
||||
"openai",
|
||||
"acc1",
|
||||
100,
|
||||
10,
|
||||
20,
|
||||
"abc123-def456-ghi789"
|
||||
);
|
||||
db.prepare(
|
||||
`INSERT OR REPLACE INTO call_logs (id, timestamp, method, path, status, model, provider, account, duration, tokens_in, tokens_out, correlation_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
||||
).run("log-2", now, "POST", "/v1/chat/completions", 200, "claude-3", "anthropic", "acc2", 200, 15, 30, "xyz999-uvw888-tsr777");
|
||||
).run(
|
||||
"log-2",
|
||||
now,
|
||||
"POST",
|
||||
"/v1/chat/completions",
|
||||
200,
|
||||
"claude-3",
|
||||
"anthropic",
|
||||
"acc2",
|
||||
200,
|
||||
15,
|
||||
30,
|
||||
"xyz999-uvw888-tsr777"
|
||||
);
|
||||
db.prepare(
|
||||
`INSERT OR REPLACE INTO call_logs (id, timestamp, method, path, status, model, provider, account, duration, tokens_in, tokens_out, correlation_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
||||
).run("log-3", now, "POST", "/v1/chat/completions", 500, "gpt-4", "openai", "acc1", 50, 0, 0, null);
|
||||
).run(
|
||||
"log-3",
|
||||
now,
|
||||
"POST",
|
||||
"/v1/chat/completions",
|
||||
500,
|
||||
"gpt-4",
|
||||
"openai",
|
||||
"acc1",
|
||||
50,
|
||||
0,
|
||||
0,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
// ── Exact match ───────────────────────────────────────────────────────────
|
||||
|
|
@ -72,11 +111,24 @@ test("correlationId substring match returns multiple when shared", async () => {
|
|||
db.prepare(
|
||||
`INSERT OR REPLACE INTO call_logs (id, timestamp, method, path, status, model, provider, account, duration, tokens_in, tokens_out, correlation_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
||||
).run("log-4", now, "POST", "/v1/chat/completions", 200, "gpt-4", "openai", "acc1", 100, 10, 20, "abc123-RETRY-suffix");
|
||||
).run(
|
||||
"log-4",
|
||||
now,
|
||||
"POST",
|
||||
"/v1/chat/completions",
|
||||
200,
|
||||
"gpt-4",
|
||||
"openai",
|
||||
"acc1",
|
||||
100,
|
||||
10,
|
||||
20,
|
||||
"abc123-RETRY-suffix"
|
||||
);
|
||||
|
||||
const results = await callLogs.getCallLogs({ correlationId: "abc123" });
|
||||
assert.equal(results.length, 2);
|
||||
const ids = results.map((r: any) => r.id).sort();
|
||||
const ids = results.map((r: { id: string }) => r.id).sort();
|
||||
assert.deepEqual(ids, ["log-1", "log-4"]);
|
||||
});
|
||||
|
||||
|
|
@ -94,7 +146,7 @@ test("rows with null correlationId are excluded from substring search", async ()
|
|||
seedLogs();
|
||||
// Search for a unique substring that only matches log-1
|
||||
const results = await callLogs.getCallLogs({ correlationId: "ghi789" });
|
||||
const ids = results.map((r: any) => r.id);
|
||||
const ids = results.map((r: { id: string }) => r.id);
|
||||
assert.ok(!ids.includes("log-3"), "null correlation_id rows must be excluded");
|
||||
assert.equal(results.length, 1);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -162,10 +162,10 @@ test("KiroExecutor.transformRequest removes the top-level model field", () => {
|
|||
|
||||
const result = executor.transformRequest("kiro-model", body, true, {});
|
||||
assert.equal("model" in result, false);
|
||||
assert.equal(
|
||||
(result as any).conversationState.currentMessage.userInputMessage.modelId,
|
||||
"kiro-model"
|
||||
);
|
||||
const kiroResult = result as unknown as {
|
||||
conversationState: { currentMessage: { userInputMessage: { modelId: string } } };
|
||||
};
|
||||
assert.equal(kiroResult.conversationState.currentMessage.userInputMessage.modelId, "kiro-model");
|
||||
});
|
||||
|
||||
test("KiroExecutor.transformRequest forwards additionalModelRequestFields (thinking) to AWS", () => {
|
||||
|
|
@ -182,7 +182,10 @@ test("KiroExecutor.transformRequest forwards additionalModelRequestFields (think
|
|||
},
|
||||
};
|
||||
|
||||
const result = executor.transformRequest("kiro-model", body, true, {}) as any;
|
||||
const result = executor.transformRequest("kiro-model", body, true, {}) as unknown as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
// The thinking control must survive the strict allowlist — otherwise graded
|
||||
// reasoning never reaches CodeWhisperer (the field the openai-to-kiro
|
||||
// translator builds would be silently dropped).
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ test("saveCallLog persists to DB with correlationId", async () => {
|
|||
|
||||
const row = db
|
||||
.prepare("SELECT id, correlation_id, status, model FROM call_logs WHERE id = ?")
|
||||
.get(testId) as any;
|
||||
.get(testId) as Record<string, unknown>;
|
||||
assert.ok(row, "row should exist in call_logs");
|
||||
assert.equal(row.id, testId);
|
||||
assert.equal(row.correlation_id, "test-correlation-id-123");
|
||||
|
|
@ -50,7 +50,7 @@ test("saveCallLog persists null correlationId when not provided", async () => {
|
|||
|
||||
const row = db
|
||||
.prepare("SELECT id, correlation_id FROM call_logs WHERE id = ?")
|
||||
.get(testId) as any;
|
||||
.get(testId) as Record<string, unknown>;
|
||||
assert.ok(row, "row should exist");
|
||||
assert.equal(row.correlation_id, null, "correlation_id should be null when not provided");
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ test("getCallLogs returns correlationId", async () => {
|
|||
});
|
||||
|
||||
const logs = await getCallLogs({ limit: 100 });
|
||||
const found = logs.find((l: any) => l.id === testId);
|
||||
const found = logs.find((l: { id: string }) => l.id === testId);
|
||||
assert.ok(found, "log entry should be found via getCallLogs");
|
||||
assert.equal(found.correlationId, "cid-roundtrip-test");
|
||||
|
||||
|
|
@ -83,12 +83,12 @@ test("getCallLogs returns correlationId", async () => {
|
|||
|
||||
test("call_logs table has correlation_id column", () => {
|
||||
const db = getDbInstance();
|
||||
const columns = db.prepare("PRAGMA table_info(call_logs)").all() as any[];
|
||||
const colNames = columns.map((c: any) => c.name);
|
||||
const columns = db.prepare("PRAGMA table_info(call_logs)").all() as { name: string }[];
|
||||
const colNames = columns.map((c) => c.name);
|
||||
assert.ok(colNames.includes("correlation_id"), "call_logs should have correlation_id column");
|
||||
|
||||
const indexes = db.prepare("PRAGMA index_list(call_logs)").all() as any[];
|
||||
const idxNames = indexes.map((i: any) => i.name);
|
||||
const indexes = db.prepare("PRAGMA index_list(call_logs)").all() as { name: string }[];
|
||||
const idxNames = indexes.map((i) => i.name);
|
||||
assert.ok(
|
||||
idxNames.includes("idx_cl_correlation_id"),
|
||||
"call_logs should have idx_cl_correlation_id index"
|
||||
|
|
@ -97,8 +97,8 @@ test("call_logs table has correlation_id column", () => {
|
|||
|
||||
test("call_logs table has model_pinned column", () => {
|
||||
const db = getDbInstance();
|
||||
const columns = db.prepare("PRAGMA table_info(call_logs)").all() as any[];
|
||||
const colNames = columns.map((c: any) => c.name);
|
||||
const columns = db.prepare("PRAGMA table_info(call_logs)").all() as { name: string }[];
|
||||
const colNames = columns.map((c) => c.name);
|
||||
assert.ok(colNames.includes("model_pinned"), "call_logs should have model_pinned column");
|
||||
});
|
||||
|
||||
|
|
@ -118,7 +118,9 @@ test("saveCallLog persists modelPinned=true as 1", async () => {
|
|||
modelPinned: true,
|
||||
});
|
||||
|
||||
const row = db.prepare("SELECT id, model_pinned FROM call_logs WHERE id = ?").get(testId) as any;
|
||||
const row = db
|
||||
.prepare("SELECT id, model_pinned FROM call_logs WHERE id = ?")
|
||||
.get(testId) as Record<string, unknown>;
|
||||
assert.ok(row, "row should exist");
|
||||
assert.equal(row.model_pinned, 1, "model_pinned should be 1 when modelPinned=true");
|
||||
|
||||
|
|
@ -141,7 +143,9 @@ test("saveCallLog persists modelPinned=false as 0", async () => {
|
|||
modelPinned: false,
|
||||
});
|
||||
|
||||
const row = db.prepare("SELECT id, model_pinned FROM call_logs WHERE id = ?").get(testId) as any;
|
||||
const row = db
|
||||
.prepare("SELECT id, model_pinned FROM call_logs WHERE id = ?")
|
||||
.get(testId) as Record<string, unknown>;
|
||||
assert.ok(row, "row should exist");
|
||||
assert.equal(row.model_pinned, 0, "model_pinned should be 0 when modelPinned=false");
|
||||
|
||||
|
|
@ -165,7 +169,7 @@ test("getCallLogs returns modelPinned boolean", async () => {
|
|||
});
|
||||
|
||||
const logs = await getCallLogs({ limit: 100 });
|
||||
const found = logs.find((l: any) => l.id === testId);
|
||||
const found = logs.find((l: { id: string }) => l.id === testId);
|
||||
assert.ok(found, "log entry should be found via getCallLogs");
|
||||
assert.equal(found.modelPinned, true, "getCallLogs should return modelPinned as boolean true");
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue