Skip to content

feat: add altimate-code check CLI command for deterministic SQL checks#453

Merged
anandgupta42 merged 7 commits intomainfrom
feat/check-command
Mar 25, 2026
Merged

feat: add altimate-code check CLI command for deterministic SQL checks#453
anandgupta42 merged 7 commits intomainfrom
feat/check-command

Conversation

@anandgupta42
Copy link
Contributor

@anandgupta42 anandgupta42 commented Mar 24, 2026

What does this PR do?

Adds a new altimate-code check CLI command that runs deterministic SQL checks without an LLM. This is the foundation for the altimate-code-actions GitHub Action to leverage all altimate-core capabilities.

Usage:

altimate-code check models/*.sql --format json --checks lint,safety,validate,policy,pii

Supported checks (7):

  • lint — 26 anti-pattern rules (L001-L026) via altimate_core.lint
  • validate — DataFusion SQL validation via altimate_core.validate
  • safety — SQL injection detection (10 rules) via altimate_core.safety
  • policy — YAML guardrail enforcement via altimate_core.policy
  • pii — PII column detection via altimate_core.query_pii
  • semantic — Semantic validation (cartesian, NULL, JOINs) via altimate_core.semantics
  • grade — SQL quality grading (A-F) via altimate_core.grade

Key design decisions:

  • Does NOT call bootstrap() — no session, database, or server needed
  • Calls Dispatcher.call() → altimate-core napi-rs (proper architecture)
  • JSON output to stdout, diagnostics to stderr
  • --fail-on controls exit code for CI gating
  • All checks wrapped in try/catch for graceful degradation

Type of change

  • New feature

How did you verify your code works?

  • TypeScript compiles (only pre-existing module resolution errors)
  • Marker compliance passes
  • Prettier passes

Checklist

  • Code follows project conventions
  • Uses altimate_change markers for upstream-shared files
  • No direct altimate-core import (routes through Dispatcher)

Summary by CodeRabbit

  • New Features
    • Added a top-level check CLI command for deterministic SQL checks (lint, validate, safety, policy, PII, semantic, grade) with file auto-discovery, glob support, batching, severity filtering, JSON or text output, duration reporting, and configurable CI-friendly exit behavior.
  • Behavior
    • Continues across files/checks on individual failures by emitting error findings instead of aborting.
  • Documentation
    • Full usage docs and CLI reference with examples for CI/hooks and output formats.
  • Tests
    • Added unit and end-to-end tests covering severity, aggregation, formatting, exit semantics, and robustness.

Add a new `check` subcommand that runs deterministic SQL analysis
(lint, validate, safety, policy, PII, semantic, grade) without
requiring an LLM. The command:

- Accepts SQL files as positional args or globs (defaults to `**/*.sql`)
- Calls `Dispatcher.call()` for each check category (no direct napi imports)
- Processes files in batches of 10 for concurrency
- Supports `--format json|text`, `--severity`, `--fail-on` flags
- Outputs diagnostics to stderr, structured JSON to stdout
- Does NOT call `bootstrap()` — no session/db/server needed
- Registered in `index.ts` with proper `altimate_change` markers
Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai
Copy link

coderabbitai bot commented Mar 24, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Adds a new deterministic CLI command check that discovers SQL files (globs/default), runs multiple non-LLM backend checks via dispatcher calls, normalizes and filters findings by severity, aggregates per-check results, and emits JSON or text output with configurable fail-on exit semantics. (50 words)

Changes

Cohort / File(s) Summary
Check Command
packages/opencode/src/cli/cmd/check.ts
New CLI command implementing file discovery/globbing, schema/policy loading, per-file/per-check dispatcher calls, per-check error isolation (emit error-findings instead of abort), normalization into Finding[], severity filtering, aggregation, output formatting, and exit-code logic. Attention: batching, error-isolation, and exit-condition logic.
Check Helpers
packages/opencode/src/cli/cmd/check-helpers.ts
New helper module exporting types (Finding, CheckCategoryResult, CheckOutput), VALID_CHECKS, SEVERITY_RANK, and utilities: normalizeSeverity, filterBySeverity, toCategoryResult, buildCheckOutput, and formatText. Attention: severity ordering and text/json formatting semantics.
CLI Registration & Middleware
packages/opencode/src/index.ts
Registers CheckCommand with yargs and conditionally skips one-time DB migration when the invoked command is check (preserves previous behavior otherwise). Minor logging indentation change.
Documentation
docs/docs/usage/check.md, docs/docs/usage/cli.md, docs/mkdocs.yml
Adds full documentation and examples for the check command, updates CLI subcommands table, and adds navigation entry to docs site.
Unit Tests (helpers)
packages/opencode/test/cli/check.test.ts
New tests for helper utilities: severity normalization, severity filtering, aggregation counts, text formatting, and buildCheckOutput pass/fail logic. Attention: ensure tests match helper semantics and message/location formatting.
E2E Tests (CLI)
packages/opencode/test/cli/check-e2e.test.ts
Comprehensive E2E suite mocking Dispatcher and file discovery to exercise CLI flows, exit-code semantics, severity filtering, dispatcher failure modes, edge-case inputs, and output stability (JSON/text).

Sequence Diagram

sequenceDiagram
    participant User as User/CLI
    participant Cmd as Check Command
    participant FileIO as File I/O
    participant Dispatcher as Dispatcher Backends
    participant Normalizer as Result Normalizer
    participant Formatter as Output Formatter
    participant Proc as Process/Exit

    User->>Cmd: invoke `altimate-code check` with options
    Cmd->>FileIO: discover/expand globs and read files
    FileIO-->>Cmd: list of SQL files / file contents
    Cmd->>FileIO: read schema & policy files (if provided)
    FileIO-->>Cmd: schema/policy contents
    Cmd->>Dispatcher: batch calls per-file per-check (lint, validate, safety, policy, pii, semantic, grade)
    Dispatcher-->>Cmd: raw backend responses
    Cmd->>Normalizer: map responses -> `Finding[]` (severity, message, location, code, rule, suggestion)
    Normalizer-->>Cmd: normalized findings
    Cmd->>Cmd: filter by `--severity`, aggregate per-category, compute pass/fail (`--fail-on`)
    Cmd->>Formatter: format as JSON or human-readable text
    Formatter-->>Cmd: formatted report
    Cmd->>User: print report and duration
    alt pass
        Cmd->>Proc: exit 0
    else fail
        Cmd->>Proc: set exitCode 1 (allowing cleanup)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • suryaiyer95

Poem

🐇 I hopped through SQL files, one by one,
Seven checks shining beneath the sun,
Findings sorted, trimmed, and neat,
Errors flagged with careful feet,
The rabbit nods — the run is done.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding a new CLI command called 'altimate-code check' for deterministic SQL checks without an LLM.
Description check ✅ Passed The description covers what changed, why, and includes a comprehensive test plan; however, it doesn't explicitly state whether the CHANGELOG was updated as required by the template.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/check-command

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/opencode/src/cli/cmd/check.ts`:
- Around line 529-545: The CI gating (pass/fail) is being computed from the
filtered `results` so flags like `--severity error --fail-on warning` can bypass
failure; instead compute counts from the raw unfiltered findings (`allResults`)
before applying `filterBySeverity`. Update the logic around
`allFindings`/`errors`/`warnings` to derive these counts from
Object.values(allResults).flatMap(...) (use the original raw findings) and keep
the display `results` = toCategoryResult(filterBySeverity(...)) as-is; ensure
`failOn`/`pass` decisions use the raw counts and not the filtered `results`.
- Around line 91-99: The fallback severity branches are dead because
normalizeSeverity() always returns a value; change each severity expression to
only call normalizeSeverity when the upstream severity is present and otherwise
use the intended default. For example, replace expressions like
normalizeSeverity(f.severity) || ("error" as const) with a guard such as
(f.severity != null ? normalizeSeverity(f.severity) : ("error" as const)), and
apply the same pattern for the other locations that currently use || ("info" as
const) or similar so missing severities yield the correct default instead of
being mapped to warning.
- Around line 253-272: runGrade currently only maps recommendation-like findings
and drops the actual grade returned by altimate_core.grade; update runGrade to
extract the grade/score from result.data (e.g., result.data.grade or
result.data.score) and attach it into the CheckCategoryResult metadata so
downstream formatting can print it. Specifically, in runGrade (and the similar
mappings at the other spots noted) return or include a metadata object on the
category result containing the raw grade value (e.g., metadata: { grade: <value>
}) and ensure the code paths that build results.grade/CheckCategoryResult
preserve and pass that metadata through to the formatter that prints --checks
grade. Locate the mapping logic in runGrade and the other grade-handling blocks
and add the grade extraction and metadata insertion while leaving existing
finding mapping intact.
- Around line 413-416: Replace direct process.exit() invocations in the check
command handler with setting process.exitCode and returning so the outer finally
block can run; specifically, in the validation branch checking checks.length
(currently calling process.exit()), set process.exitCode = 1 and return; do the
same for the other validation/error branches (the pre-check validation errors
and the "policy file read error" branch) by assigning process.exitCode = 1 then
returning; for the "no SQL files found" branch return without changing exitCode;
and for the final "checks failed" branch set process.exitCode = 1 and return
instead of calling process.exit(). Ensure all occurrences of process.exit() in
the check command handler are replaced accordingly so Telemetry.shutdown() in
the outer finally will execute.

In `@packages/opencode/src/index.ts`:
- Around line 206-207: CheckCommand is being registered through the global
middleware path which triggers JsonMigration.run() and full stateful
initialization; move CheckCommand to a fast path that bypasses the middleware
and migration so deterministic SQL checks only use Dispatcher.call() without
starting JsonMigration or other stateful init. Concretely: register or handle
CheckCommand before applying the middleware chain (the code that runs lines
96-175 and calls JsonMigration.run()), or add a short-circuit in the command
dispatcher that detects the CheckCommand name and directly invokes
Dispatcher.call() for deterministic SQL checks, ensuring no code paths call
JsonMigration.run() or any stateful initialization when handling CheckCommand.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7dfcf22d-e218-4df6-b07a-3f237f1933db

📥 Commits

Reviewing files that changed from the base of the PR and between 12ed190 and b2c0375.

📒 Files selected for processing (2)
  • packages/opencode/src/cli/cmd/check.ts
  • packages/opencode/src/index.ts

Comment on lines +91 to +99
return errors.map((f) => ({
file,
line: f.line as number | undefined,
column: f.column as number | undefined,
code: f.code as string | undefined,
rule: "validate",
severity: normalizeSeverity(f.severity as string) || ("error" as const),
message: (f.message ?? f.description ?? "") as string,
suggestion: f.suggestion as string | undefined,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

The per-check fallback severities never fire.

normalizeSeverity() always returns a value, so the || "error" / || "info" branches on Lines 97, 169, and 269 are dead code. Missing severities are therefore classified as warning, which can let validate/policy failures slip past --fail-on error and upgrades grade recommendations from info to warning.

Suggested fix
-        severity: normalizeSeverity(f.severity as string) || ("error" as const),
+        severity: f.severity ? normalizeSeverity(f.severity as string) : "error",
...
-        severity: normalizeSeverity(f.severity as string) || ("error" as const),
+        severity: f.severity ? normalizeSeverity(f.severity as string) : "error",
...
-      severity: normalizeSeverity(f.severity as string) || ("info" as const),
+      severity: f.severity ? normalizeSeverity(f.severity as string) : "info",

Also applies to: 163-170, 263-270, 283-289

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/src/cli/cmd/check.ts` around lines 91 - 99, The fallback
severity branches are dead because normalizeSeverity() always returns a value;
change each severity expression to only call normalizeSeverity when the upstream
severity is present and otherwise use the intended default. For example, replace
expressions like normalizeSeverity(f.severity) || ("error" as const) with a
guard such as (f.severity != null ? normalizeSeverity(f.severity) : ("error" as
const)), and apply the same pattern for the other locations that currently use
|| ("info" as const) or similar so missing severities yield the correct default
instead of being mapped to warning.

…eck` command

- Add `docs/docs/usage/check.md` with full documentation covering all 7 check
  types, CLI options, JSON output schema, policy file format, schema file format,
  severity levels, CI/CD integration (GitHub Actions, pre-commit, GitLab CI),
  and real-world usage examples
- Update `docs/docs/usage/cli.md` to reference the `check` command in the
  subcommands table
- Add `check` page to `docs/mkdocs.yml` navigation under Interfaces
- Extract helper functions (`normalizeSeverity`, `filterBySeverity`,
  `toCategoryResult`, `formatText`, `buildCheckOutput`) into
  `check-helpers.ts` for testability
- Refactor `check.ts` to import from `check-helpers.ts` (no behavior change)
- Add 53 unit tests covering: severity normalization, severity filtering,
  category result building, text formatting, output assembly, constants
  validation, and edge cases

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/docs/usage/check.md`:
- Around line 154-163: Update the fenced code block that shows the CLI output by
adding a language specifier to the opening triple-backticks (e.g., change ``` to
```text or ```plaintext) so linters and renderers treat it as plain text and
enable proper highlighting; locate the triple-backtick block that begins with
"Checked 3 file(s) with [lint, safety]" and modify its opening fence
accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ad341f43-688d-40a6-8206-26a11105daa5

📥 Commits

Reviewing files that changed from the base of the PR and between b2c0375 and 55504fa.

📒 Files selected for processing (6)
  • docs/docs/usage/check.md
  • docs/docs/usage/cli.md
  • docs/mkdocs.yml
  • packages/opencode/src/cli/cmd/check-helpers.ts
  • packages/opencode/src/cli/cmd/check.ts
  • packages/opencode/test/cli/check.test.ts
✅ Files skipped from review due to trivial changes (2)
  • docs/docs/usage/cli.md
  • docs/mkdocs.yml

anandgupta42 and others added 5 commits March 24, 2026 16:46
- 58 new tests covering full handler flow with mocked `Dispatcher.call()`
- E2E: all 7 check types, `--fail-on` exit codes, `--severity` filtering,
  `--policy` validation, unknown check names, schema resolution, batching,
  text/JSON output, mixed success/failure across checks
- Adversarial: null bytes, shell metacharacters, 100K-char lines, Unicode/emoji,
  CRLF, spaces in filenames, deeply nested paths, malformed policy JSON, 1MB
  policy files, undefined/null finding fields, 5000 findings, XSS-like content,
  non-string severity, `__proto__` pollution, binary `.sql` content, symlinks,
  directory with `.sql` extension, duplicate file args, empty checks string
- Fix: `normalizeSeverity()` now handles non-string inputs without crashing
  (previously threw on numeric/boolean/object severity from Dispatcher)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. `--fail-on` now evaluates UNFILTERED findings before `--severity`
   filtering. Previously, `--severity error --fail-on warning` would
   false-pass because warnings were filtered out before exit logic.

2. Removed unused CLI options (`--dialect`, `--dbt-project`, `--manifest`)
   that were documented but had no effect — misleading for CI users.

3. `runPii` now checks `result.success` before processing data,
   consistent with all other check runners.

4. Dispatcher failures now emit error-severity findings instead of
   silently returning `[]`. A broken native bridge no longer reports
   PASS with zero findings.

Also:
- Use `buildCheckOutput()` helper instead of duplicated inline logic
- Remove dead `|| ("error" as const)` fallbacks after `normalizeSeverity`
- Add 4 new tests: severity/fail-on interaction, runPii failure,
  Dispatcher failure exit code

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Replace `process.exit()` with `process.exitCode` + `return` so the
   outer `finally` block in `index.ts` can run `Telemetry.shutdown()`.

2. Preserve A-F grade value from `altimate_core.grade` response in
   `CheckCategoryResult` metadata (`grade`, `score` fields).

3. Skip DB migration for `check` command — it only needs `Dispatcher`
   and has zero database dependencies. Prevents startup failure on
   read-only CI environments and removes multi-minute overhead.

4. Remove unused `--dialect`, `--dbt-project`, `--manifest` from docs
   options table (code already removed in prior commit).

5. Add `text` language specifier to fenced code block in `check.md`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…_context`

`schema_context` is already optional (`?`) in the Dispatcher types.
The `undefined as any` casts were unnecessary type safety bypasses.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@anandgupta42 anandgupta42 merged commit 79d7c56 into main Mar 25, 2026
8 of 10 checks passed
@anandgupta42 anandgupta42 deleted the feat/check-command branch March 25, 2026 02:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants