-
Notifications
You must be signed in to change notification settings - Fork 137
feat: dbt_project_health tool — reuse altimate-core dbt health checks #1030
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| --- | ||
| description: infer a dbt health-check config from the project's own conventions and write .altimate/dbt-health.yml | ||
| agent: build | ||
| subtask: true | ||
| --- | ||
|
|
||
| Generate a dbt health-check configuration by inferring it from a dbt project's **existing conventions** (deterministic — no guessing). | ||
|
|
||
| ## Target project | ||
|
|
||
| Use `$ARGUMENTS` as the dbt project directory if provided. Otherwise, locate the dbt project in the current worktree by finding the directory that contains a `dbt_project.yml` (run `project_scan` if you need to discover it). If there are **multiple** dbt projects, do this for **each** one — every project gets its own `.altimate/dbt-health.yml`. | ||
|
|
||
| ## Steps | ||
|
|
||
| 1. For each target project directory, call the **`dbt_health_config`** tool: | ||
| `dbt_health_config({ project_dir: "<dir>" })` | ||
| This deterministically infers the config from the project (modal tags / meta keys / tests, configured schemas & databases, naming contracts, distribution-ratcheted thresholds) and writes it to `<dir>/.altimate/dbt-health.yml`. | ||
|
|
||
| 2. Then run **`dbt_project_health`** on the same directory: | ||
| `dbt_project_health({ project_dir: "<dir>" })` | ||
| It auto-discovers the freshly written `.altimate/dbt-health.yml`, so the report now reflects the inferred rules. | ||
|
|
||
| 3. Summarize for the user: the path(s) written, which config-driven checks were activated (tags, meta keys, tests, naming contracts, parent schema/database whitelists, thresholds), and the resulting finding counts by severity. Tell them the file is committed with the project and can be hand-edited — re-running this command regenerates it deterministically. | ||
|
|
||
| Do not fabricate values; everything comes from the two tools above. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -267,6 +267,23 @@ export function registerAll(): void { | |
| return fail(e) | ||
| } | ||
| }) | ||
| // dbt project health checks — reads the dbt project files directly (no manifest required). | ||
| register("altimate_core.dbt_project_health", async (params) => { | ||
| try { | ||
| const json = core.dbtProjectHealth(params.project_dir, params.config_json, params.catalog_path) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MINOR — no version guard on the new exports This file already establishes the guard pattern for exactly this situation at line 176: params.base_sql && typeof core.lintDiff === "function"added because Fix: guard with |
||
| return ok(true, { findings: JSON.parse(json) }) | ||
| } catch (e) { | ||
| return fail(e) | ||
| } | ||
| }) | ||
| // Deterministically infer a dbt health-check config (YAML) from a project's conventions. | ||
| register("altimate_core.dbt_health_infer_config", async (params) => { | ||
| try { | ||
| return ok(true, { config: core.dbtHealthInferConfig(params.project_dir) }) | ||
| } catch (e) { | ||
| return fail(e) | ||
| } | ||
| }) | ||
|
Comment on lines
+270
to
+286
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CRITICAL — these two registrations break
const coreCount = registered.filter((m) => m.startsWith("altimate_core.")).length
expect(coreCount).toBe(ALL_METHODS.length)Registering two more methods without adding them to the array makes it 45 vs 43. This is a deterministic CI failure, not a coverage gap. Fix: add |
||
| // altimate_change end | ||
|
|
||
| // 7. altimate_core.fix | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,55 @@ | ||||||||||||||||||||||||||||||||||||||||||||
| import { mkdir } from "node:fs/promises" | ||||||||||||||||||||||||||||||||||||||||||||
| import { dirname } from "node:path" | ||||||||||||||||||||||||||||||||||||||||||||
| import z from "zod" | ||||||||||||||||||||||||||||||||||||||||||||
| import { Tool } from "../../tool/tool" | ||||||||||||||||||||||||||||||||||||||||||||
| import { Dispatcher } from "../native" | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| /** Relative path (from the dbt project root) where the inferred config is written. */ | ||||||||||||||||||||||||||||||||||||||||||||
| export const DBT_HEALTH_CONFIG_RELPATH = ".altimate/dbt-health.yml" | ||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MINOR — this constant isn't used by the reader
Fix: export the directory and basename (or a |
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| export const DbtHealthConfigTool = Tool.define("dbt_health_config", { | ||||||||||||||||||||||||||||||||||||||||||||
| description: | ||||||||||||||||||||||||||||||||||||||||||||
| "Deterministically infer a dbt health-check config from a dbt project's EXISTING conventions (modal tags/meta keys/tests, configured schemas & databases, naming contracts, distribution-ratcheted thresholds) and write it to <project_dir>/.altimate/dbt-health.yml. This activates the config-driven governance checks (which are no-ops until configured). Per-project: each dbt project gets its own config file. Reproducible — no LLM, same project always yields the same file.", | ||||||||||||||||||||||||||||||||||||||||||||
| parameters: z.object({ | ||||||||||||||||||||||||||||||||||||||||||||
| project_dir: z.string().describe("Path to the dbt project root (the directory containing dbt_project.yml)"), | ||||||||||||||||||||||||||||||||||||||||||||
| write: z | ||||||||||||||||||||||||||||||||||||||||||||
| .boolean() | ||||||||||||||||||||||||||||||||||||||||||||
| .optional() | ||||||||||||||||||||||||||||||||||||||||||||
| .describe("Write the config to <project_dir>/.altimate/dbt-health.yml (default true). If false, only return the YAML."), | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+15
to
+18
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MAJOR — hand-edited config is silently destroyed
Fix: add |
||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||
| async execute(args, _ctx) { | ||||||||||||||||||||||||||||||||||||||||||||
| const result = await Dispatcher.call("altimate_core.dbt_health_infer_config", { | ||||||||||||||||||||||||||||||||||||||||||||
| project_dir: args.project_dir, | ||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| if (!result.success) { | ||||||||||||||||||||||||||||||||||||||||||||
| const error = result.error ?? "unknown error" | ||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||
| title: "dbt health config: ERROR", | ||||||||||||||||||||||||||||||||||||||||||||
| metadata: { error }, | ||||||||||||||||||||||||||||||||||||||||||||
| output: `Failed to infer dbt health config: ${error}`, | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const yaml = String((result.data as { config?: unknown }).config ?? "") | ||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [🔴 HIGH] Potential runtime Suggested change:
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
| const outPath = `${args.project_dir.replace(/\/+$/, "")}/${DBT_HEALTH_CONFIG_RELPATH}` | ||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '--- file outline ---'
ast-grep outline packages/opencode/src/altimate/tools/dbt-health-config.ts --view expanded || true
echo '--- relevant lines ---'
sed -n '1,120p' packages/opencode/src/altimate/tools/dbt-health-config.ts
echo '--- path semantics probe ---'
node - <<'JS'
const path = require('node:path');
const rel = 'dbt_health_config.yml';
const inputs = [
'/',
'/tmp/',
'C:/',
'C:/work/',
'C:\\',
'C:\\work\\',
'relative/',
];
for (const p of inputs) {
const stripped = `${p.replace(/\/+$/, '')}/${rel}`;
const joined = path.join(p, rel);
const posixJoined = path.posix.join(p, rel);
const winJoined = path.win32.join(p, rel);
console.log(JSON.stringify({ p, stripped, joined, posixJoined, winJoined }));
}
JSRepository: AltimateAI/altimate-code Length of output: 4011 🏁 Script executed: #!/bin/bash
set -euo pipefail
sed -n '1,120p' packages/opencode/src/altimate/tools/dbt-health-config.ts
node - <<'JS'
const path = require('node:path');
const rel = 'dbt_health_config.yml';
for (const p of ['/', '/tmp/', 'C:/', 'C:/work/', 'C:\\', 'C:\\work\\', 'relative/']) {
const stripped = `${p.replace(/\/+$/, '')}/${rel}`;
const joined = path.join(p, rel);
console.log(JSON.stringify({ p, stripped, joined }));
}
JSRepository: AltimateAI/altimate-code Length of output: 3259 🏁 Script executed: #!/bin/bash
set -euo pipefail
node - <<'JS'
const path = require('node:path');
const samples = [
'/.altimate/dbt-health.yml',
'C:/.altimate/dbt-health.yml',
'C:\\/.altimate/dbt-health.yml',
'C:/work/.altimate/dbt-health.yml',
'C:\\work\\/.altimate/dbt-health.yml',
'//server/share/.altimate/dbt-health.yml',
];
for (const s of samples) {
console.log(JSON.stringify({
s,
posix_dirname: path.posix.dirname(s),
win_dirname: path.win32.dirname(s),
posix_isAbs: path.posix.isAbsolute(s),
win_isAbs: path.win32.isAbsolute(s),
normalized_win: path.win32.normalize(s),
}));
}
JSRepository: AltimateAI/altimate-code Length of output: 1352 Build the output path with 🤖 Prompt for AI AgentsThere was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: The output path is built with manual slash-trimming and template concatenation, but Prompt for AI agents
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [🔴 HIGH] Unsafe path construction and potential directory traversal. The output path is constructed using simple string concatenation. If the AI agent provides an empty string, Consider importing Suggested change:
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| let written = false | ||||||||||||||||||||||||||||||||||||||||||||
| if (args.write !== false) { | ||||||||||||||||||||||||||||||||||||||||||||
| await mkdir(dirname(outPath), { recursive: true }) | ||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: The Prompt for AI agents |
||||||||||||||||||||||||||||||||||||||||||||
| await Bun.write(outPath, yaml) | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+39
to
+40
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '\n== File outline ==\n'
ast-grep outline packages/opencode/src/altimate/tools/dbt-health-config.ts --view expanded || true
printf '\n== File contents (relevant slice) ==\n'
wc -l packages/opencode/src/altimate/tools/dbt-health-config.ts
sed -n '1,220p' packages/opencode/src/altimate/tools/dbt-health-config.ts | cat -n
printf '\n== Search for related path / symlink handling ==\n'
rg -n "symlink|realpath|canonical|containment|mkdir\\(|Bun\\.write\\(|dbt-health.yml|\\.altimate|project_dir|projectDir|outPath" packages/opencode/src -SRepository: AltimateAI/altimate-code Length of output: 41320 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '\n== util/filesystem.ts excerpt ==\n'
sed -n '200,280p' packages/opencode/src/util/filesystem.ts | cat -n
printf '\n== write helpers / containment usages ==\n'
rg -n "containsReal|containsPath|mkdir\\(|writeFile\\(|Bun\\.write\\(" packages/opencode/src/util packages/opencode/src/altimate packages/opencode/src/cli -SRepository: AltimateAI/altimate-code Length of output: 6872 Prevent symlink escapes in the write path. 🤖 Prompt for AI AgentsSource: Coding guidelines |
||||||||||||||||||||||||||||||||||||||||||||
| written = true | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+37
to
+42
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [🔴 HIGH] Unhandled exceptions in file system operations and inconsistent FS API usage.
Suggested change:
Suggested change
Comment on lines
+35
to
+42
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CRITICAL — this write has none of the repo's write guards
This is the first write-capable tool under Three concrete failure modes:
Fix: resolve |
||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const checkCount = (yaml.match(/^ {2}\S/gm) ?? []).length | ||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MINOR —
Fix: have the core return the count, parse the YAML, or drop the claim from the title. |
||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||
| title: written | ||||||||||||||||||||||||||||||||||||||||||||
| ? `dbt health config written (${checkCount} checks tuned) → ${outPath}` | ||||||||||||||||||||||||||||||||||||||||||||
| : `dbt health config inferred (${checkCount} checks tuned)`, | ||||||||||||||||||||||||||||||||||||||||||||
| metadata: { path: outPath, written, project_dir: args.project_dir }, | ||||||||||||||||||||||||||||||||||||||||||||
| output: written | ||||||||||||||||||||||||||||||||||||||||||||
| ? `Wrote inferred config to ${outPath}:\n\n${yaml}` | ||||||||||||||||||||||||||||||||||||||||||||
| : `Inferred config (not written):\n\n${yaml}`, | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,100 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import z from "zod" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Tool } from "../../tool/tool" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Dispatcher } from "../native" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** A single finding returned by `altimate_core.dbt_project_health` (Rust `HealthFinding`). */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface HealthFinding { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| alias: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| resource_type: "model" | "source" | "exposure" | "macro" | "project" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| unique_id?: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| file?: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| severity: "error" | "warning" | "info" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| recommendation?: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reason_to_flag?: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| metadata?: unknown | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+15
to
+16
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MINOR — these two fields are declared but never rendered
Fix: render |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+5
to
+17
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MINOR — This interface is hand-declared here with no link to the Rust Fix: move the type into |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const SEVERITY_ORDER: Record<string, number> = { error: 0, warning: 1, info: 2 } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const DbtProjectHealthTool = Tool.define("dbt_project_health", { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Run dbt project health checks (governance, modelling, documentation, tests, sources) directly against a dbt project's files — no compiled manifest.json required. Reads .sql models (via the dbt Jinja AST parser), schema.yml properties and dbt_project.yml. Optionally uses a catalog.json for column-level checks; otherwise columns are inferred from the SQL parser.", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parameters: z.object({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| project_dir: z.string().describe("Path to the dbt project root (the directory containing dbt_project.yml)"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| config_path: z | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .string() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .optional() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .describe("Optional path to a JSON health-check config (disabled checks, severity overrides, options)"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+26
to
+29
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MINOR — this description is inaccurate and incomplete It says "path to a JSON health-check config", but auto-discovery below accepts The description also never mentions that a project-local config is auto-discovered when this is omitted, so the model can't reason about when to pass it. Fix: |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| catalog_path: z | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .string() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .optional() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .describe("Optional path to a dbt catalog.json to power column-aware checks"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async execute(args, _ctx) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MINOR —
The framework's Also: the soft-error returns omit Fix: wrap each |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Explicit config_path wins; otherwise auto-discover a per-project inferred config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // at <project_dir>/.altimate/dbt-health.{yml,yaml,json} (YAML or JSON both parse). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let config_json: string | undefined | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const candidates = args.config_path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? [args.config_path] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `${args.project_dir.replace(/\/+$/, "")}/.altimate/dbt-health.yml`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `${args.project_dir.replace(/\/+$/, "")}/.altimate/dbt-health.yaml`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `${args.project_dir.replace(/\/+$/, "")}/.altimate/dbt-health.json`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+42
to
+44
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MINOR — build these with
Fix: |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const candidate of candidates) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const file = Bun.file(candidate) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (await file.exists()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| config_json = await file.text() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+38
to
+52
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [🟠 MEDIUM] If Suggested change:
Suggested change
Comment on lines
+39
to
+52
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MAJOR — an explicit When For a governance tool this is the worst failure mode: a typo'd path yields Fix: if |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const result = await Dispatcher.call("altimate_core.dbt_project_health", { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| project_dir: args.project_dir, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| config_json, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| catalog_path: args.catalog_path, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+54
to
+58
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MAJOR — relative paths resolve against
Users will reasonably expect Fix: const projectDir = path.resolve(Instance.directory, args.project_dir)
const configPath = args.config_path ? path.resolve(projectDir, args.config_path) : undefined
const catalogPath = args.catalog_path ? path.resolve(projectDir, args.catalog_path) : undefinedPass only normalized paths to the dispatcher and report them in metadata. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!result.success) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const error = result.error ?? "unknown error" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title: "dbt health: ERROR", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| metadata: { error }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| output: `Failed to run dbt health checks: ${error}`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const findings = ((result.data.findings as HealthFinding[] | undefined) ?? []).slice() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| findings.sort( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (a, b) => (SEVERITY_ORDER[a.severity] ?? 3) - (SEVERITY_ORDER[b.severity] ?? 3) || a.code.localeCompare(b.code), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const counts = { error: 0, warning: 0, info: 0 } as Record<string, number> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const f of findings) counts[f.severity] = (counts[f.severity] ?? 0) + 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+69
to
+75
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
sed -n '1,220p' packages/opencode/src/altimate/tools/dbt-project-health.ts
printf '\n---- search HealthFinding ----\n'
rg -n "HealthFinding|findings" packages/opencode/src/altimate -g '!**/dist/**' -g '!**/build/**'Repository: AltimateAI/altimate-code Length of output: 27057 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '--- file ---\n'
nl -ba packages/opencode/src/altimate/tools/dbt-project-health.ts | sed -n '1,220p'
printf '\n--- search definitions ---\n'
rg -n "type HealthFinding|interface HealthFinding|Schema.*HealthFinding|findings:" packages/opencode/src/altimate -g '!**/dist/**' -g '!**/build/**'Repository: AltimateAI/altimate-code Length of output: 253 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- altimate-core dbt_project_health references ---'
rg -n "dbt_project_health|HealthFinding|JSON.parse\\(json\\)" packages/opencode/src/altimate/native/altimate-core.ts packages/opencode/src/altimate/native -g '!**/dist/**' -g '!**/build/**'
printf '\n%s\n' '--- dispatcher definition ---'
rg -n "class Dispatcher|export const Dispatcher|call\\(" packages/opencode/src/altimate/native packages/opencode/src/altimate -g '!**/dist/**' -g '!**/build/**'Repository: AltimateAI/altimate-code Length of output: 14037 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- native altimate_core.dbt_project_health implementation ---'
nl -ba packages/opencode/src/altimate/native/altimate-core.ts | sed -n '260,285p'
printf '\n%s\n' '--- dispatcher return typing ---'
nl -ba packages/opencode/src/altimate/native/types.ts | sed -n '1238,1260p'
printf '\n%s\n' '--- dispatcher implementation ---'
rg -n "class Dispatcher|export class Dispatcher|static async call|async call" packages/opencode/src/altimate/native packages/opencode/src/altimate -g '!**/dist/**' -g '!**/build/**'Repository: AltimateAI/altimate-code Length of output: 265 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- native altimate_core.dbt_project_health implementation ---'
nl -ba packages/opencode/src/altimate/native/altimate-core.ts | sed -n '260,285p'
printf '%s\n' '--- dispatcher return typing ---'
nl -ba packages/opencode/src/altimate/native/types.ts | sed -n '1238,1260p'
printf '%s\n' '--- dispatcher implementation ---'
rg -n "class Dispatcher|export class Dispatcher|static async call|async call" packages/opencode/src/altimate/native packages/opencode/src/altimate -g '!**/dist/**' -g '!**/build/**'Repository: AltimateAI/altimate-code Length of output: 265 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- native altimate_core.dbt_project_health implementation ---'
sed -n '268,278p' packages/opencode/src/altimate/native/altimate-core.ts | cat -n
printf '\n%s\n' '--- native types entry ---'
sed -n '1242,1254p' packages/opencode/src/altimate/native/types.ts | cat -n
printf '\n%s\n' '--- dispatcher implementation files ---'
fd -a "dispatcher*.ts" packages/opencode/src/altimate packages/opencode/src -E dist -E buildRepository: AltimateAI/altimate-code Length of output: 1545 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- dispatcher.ts ---'
sed -n '1,260p' packages/opencode/src/altimate/native/dispatcher.ts | cat -n
printf '\n%s\n' '--- AltimateCoreResult definition ---'
rg -n "type AltimateCoreResult|interface AltimateCoreResult|export type AltimateCoreResult" packages/opencode/src/altimate/native/types.ts packages/opencode/src/altimate/native -g '!**/dist/**' -g '!**/build/**'Repository: AltimateAI/altimate-code Length of output: 3918 Validate the native findings payload at runtime. 🤖 Prompt for AI AgentsSource: Coding guidelines |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title: `dbt health: ${findings.length} finding(s) — ${counts.error} error, ${counts.warning} warning, ${counts.info} info`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| metadata: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| finding_count: findings.length, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error_count: counts.error, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| warning_count: counts.warning, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| info_count: counts.info, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| output: formatFindings(findings), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function formatFindings(findings: HealthFinding[]): string { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (findings.length === 0) return "✓ No dbt health issues found." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const lines: string[] = [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (const f of findings) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const where = f.file ? ` (${f.file})` : f.unique_id ? ` (${f.unique_id})` : "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lines.push(`[${f.severity.toUpperCase()}] ${f.code} ${f.alias}${where}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+93
to
+95
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [🔵 LOW] According to the review checklist, nested ternary expressions are not allowed. Please refactor this to use an Suggested change:
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lines.push(` ${f.message}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (f.recommendation) lines.push(` → ${f.recommendation}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return lines.join("\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+90
to
+100
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MINOR — no domain-level cap on output
What's missing is that the model is never told it's seeing a partial list. Fix: cap at a domain-appropriate number and append |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CRITICAL —
0.8.0is not published, andbun.lockstill pins0.5.10.8.0does not exist on npm today. Separately,bun.lockstill resolves0.5.1at lines 273 and 642 plus all five platform binaries, and the lockfile isn't part of this PR (git log -1 -- bun.lockpoints at a pre-existing commit).Every CI job runs plain
bun install(.github/workflows/ci.yml:100,108,287,348,408,465,505), and Bun applies frozen-lockfile behaviour whenCIis set — so the manifest/lock mismatch fails the install step. If it did install from the current lock it would fetch0.5.1, which exports neitherdbtProjectHealthnordbtHealthInferConfig, and both tools would returnTypeError: core.dbtProjectHealth is not a functionon every call.The PR description already flags the ordering dependency, so this is partly known — noting it because the branch is red until that release lands.
Fix: publish
0.8.0, thenbun installand commit the regeneratedbun.lockwith the root entry and all five platform optional deps at0.8.0.One wrinkle:
bunfig.tomlsetsminimumReleaseAge = 259200(3 days) and this package is not inminimumReleaseAgeExcludes, so a freshly published0.8.0will still be refused for three days after publish. Add it to the excludes list or plan the timing.