Skip to content

Commit 3aa877a

Browse files
authored
Merge branch 'main' into fix/ai-5975-tool-error-propagation
2 parents e2d07c7 + 16c38bb commit 3aa877a

8 files changed

Lines changed: 2792 additions & 2 deletions

File tree

docs/docs/usage/check.md

Lines changed: 448 additions & 0 deletions
Large diffs are not rendered by default.

docs/docs/usage/cli.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ altimate --agent analyst
2222
| Command | Description |
2323
| ----------- | ------------------------------ |
2424
| `run` | Run a prompt non-interactively |
25+
| `check` | Run deterministic SQL checks (no LLM required) -- see [SQL Check](check.md) |
2526
| `serve` | Start the HTTP API server |
2627
| `web` | Start the web UI |
2728
| `agent` | Agent management |

docs/mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ nav:
101101
- Interfaces:
102102
- TUI: usage/tui.md
103103
- CLI: usage/cli.md
104+
- SQL Check: usage/check.md
104105
- Web UI: usage/web.md
105106
- CI: usage/ci-headless.md
106107
- IDE: usage/ide.md
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// altimate_change start — check-helpers: extracted helpers for deterministic SQL check command
2+
// These are exported separately so they can be unit-tested without importing
3+
// the full CLI command (which has side-effects via yargs).
4+
5+
// ---------------------------------------------------------------------------
6+
// Types
7+
// ---------------------------------------------------------------------------
8+
9+
export interface Finding {
10+
file: string
11+
line?: number
12+
column?: number
13+
code?: string
14+
rule?: string
15+
severity: "error" | "warning" | "info"
16+
message: string
17+
suggestion?: string
18+
}
19+
20+
export interface CheckCategoryResult {
21+
findings: Finding[]
22+
error_count: number
23+
warning_count: number
24+
[key: string]: unknown
25+
}
26+
27+
export interface CheckOutput {
28+
version: 1
29+
files_checked: number
30+
checks_run: string[]
31+
schema_resolved: boolean
32+
results: Record<string, CheckCategoryResult>
33+
summary: {
34+
total_findings: number
35+
errors: number
36+
warnings: number
37+
info: number
38+
pass: boolean
39+
}
40+
}
41+
42+
export type Severity = "error" | "warning" | "info"
43+
44+
export const SEVERITY_RANK: Record<Severity, number> = { error: 2, warning: 1, info: 0 }
45+
46+
export const VALID_CHECKS = new Set(["lint", "validate", "safety", "policy", "pii", "semantic", "grade"])
47+
48+
// ---------------------------------------------------------------------------
49+
// Helpers
50+
// ---------------------------------------------------------------------------
51+
52+
export function normalizeSeverity(s?: string | unknown): Severity {
53+
if (!s || typeof s !== "string") return "warning"
54+
const lower = s.toLowerCase()
55+
if (lower === "error" || lower === "fatal" || lower === "critical") return "error"
56+
if (lower === "warning" || lower === "warn") return "warning"
57+
return "info"
58+
}
59+
60+
export function filterBySeverity(findings: Finding[], minSeverity: Severity): Finding[] {
61+
const minRank = SEVERITY_RANK[minSeverity]
62+
return findings.filter((f) => SEVERITY_RANK[f.severity] >= minRank)
63+
}
64+
65+
export function toCategoryResult(findings: Finding[]): CheckCategoryResult {
66+
return {
67+
findings,
68+
error_count: findings.filter((f) => f.severity === "error").length,
69+
warning_count: findings.filter((f) => f.severity === "warning").length,
70+
}
71+
}
72+
73+
// ---------------------------------------------------------------------------
74+
// Text formatter
75+
// ---------------------------------------------------------------------------
76+
77+
export function formatText(output: CheckOutput): string {
78+
const lines: string[] = []
79+
80+
lines.push(`Checked ${output.files_checked} file(s) with [${output.checks_run.join(", ")}]`)
81+
if (output.schema_resolved) {
82+
lines.push("Schema: resolved")
83+
}
84+
lines.push("")
85+
86+
for (const [category, catResult] of Object.entries(output.results)) {
87+
if (catResult.findings.length === 0) continue
88+
lines.push(`--- ${category.toUpperCase()} ---`)
89+
for (const f of catResult.findings) {
90+
const loc = f.line ? `:${f.line}${f.column ? `:${f.column}` : ""}` : ""
91+
const rule = f.rule ? ` [${f.rule}]` : ""
92+
lines.push(` ${f.severity.toUpperCase()} ${f.file}${loc}${rule}: ${f.message}`)
93+
if (f.suggestion) {
94+
lines.push(` suggestion: ${f.suggestion}`)
95+
}
96+
}
97+
lines.push("")
98+
}
99+
100+
const s = output.summary
101+
lines.push(`${s.total_findings} finding(s): ${s.errors} error(s), ${s.warnings} warning(s), ${s.info} info`)
102+
lines.push(s.pass ? "PASS" : "FAIL")
103+
104+
return lines.join("\n")
105+
}
106+
107+
// ---------------------------------------------------------------------------
108+
// Output builder
109+
// ---------------------------------------------------------------------------
110+
111+
export function buildCheckOutput(opts: {
112+
filesChecked: number
113+
checksRun: string[]
114+
schemaResolved: boolean
115+
results: Record<string, CheckCategoryResult>
116+
failOn: "none" | "warning" | "error"
117+
}): CheckOutput {
118+
const allFindings = Object.values(opts.results).flatMap((r) => r.findings)
119+
const errors = allFindings.filter((f) => f.severity === "error").length
120+
const warnings = allFindings.filter((f) => f.severity === "warning").length
121+
const info = allFindings.filter((f) => f.severity === "info").length
122+
123+
let pass = true
124+
if (opts.failOn === "error" && errors > 0) pass = false
125+
if (opts.failOn === "warning" && (errors > 0 || warnings > 0)) pass = false
126+
127+
return {
128+
version: 1,
129+
files_checked: opts.filesChecked,
130+
checks_run: opts.checksRun,
131+
schema_resolved: opts.schemaResolved,
132+
results: opts.results,
133+
summary: {
134+
total_findings: allFindings.length,
135+
errors,
136+
warnings,
137+
info,
138+
pass,
139+
},
140+
}
141+
}
142+
// altimate_change end

0 commit comments

Comments
 (0)