altimate-code 0.4.9 → 0.5.1

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +22 -60
  3. package/package.json +54 -14
  4. package/postinstall.mjs +35 -0
  5. package/skills/cost-report/SKILL.md +134 -0
  6. package/skills/data-viz/SKILL.md +135 -0
  7. package/skills/data-viz/references/component-guide.md +394 -0
  8. package/skills/dbt-analyze/SKILL.md +130 -0
  9. package/skills/dbt-analyze/references/altimate-dbt-commands.md +66 -0
  10. package/skills/dbt-analyze/references/lineage-interpretation.md +58 -0
  11. package/skills/dbt-develop/SKILL.md +151 -0
  12. package/skills/dbt-develop/references/altimate-dbt-commands.md +66 -0
  13. package/skills/dbt-develop/references/common-mistakes.md +49 -0
  14. package/skills/dbt-develop/references/incremental-strategies.md +118 -0
  15. package/skills/dbt-develop/references/layer-patterns.md +158 -0
  16. package/skills/dbt-develop/references/medallion-architecture.md +125 -0
  17. package/skills/dbt-develop/references/yaml-generation.md +90 -0
  18. package/skills/dbt-docs/SKILL.md +99 -0
  19. package/skills/dbt-docs/references/altimate-dbt-commands.md +66 -0
  20. package/skills/dbt-docs/references/documentation-standards.md +94 -0
  21. package/skills/dbt-test/SKILL.md +121 -0
  22. package/skills/dbt-test/references/altimate-dbt-commands.md +66 -0
  23. package/skills/dbt-test/references/custom-tests.md +59 -0
  24. package/skills/dbt-test/references/schema-test-patterns.md +103 -0
  25. package/skills/dbt-test/references/unit-test-guide.md +121 -0
  26. package/skills/dbt-troubleshoot/SKILL.md +187 -0
  27. package/skills/dbt-troubleshoot/references/altimate-dbt-commands.md +66 -0
  28. package/skills/dbt-troubleshoot/references/compilation-errors.md +57 -0
  29. package/skills/dbt-troubleshoot/references/runtime-errors.md +71 -0
  30. package/skills/dbt-troubleshoot/references/test-failures.md +95 -0
  31. package/skills/lineage-diff/SKILL.md +64 -0
  32. package/skills/pii-audit/SKILL.md +117 -0
  33. package/skills/query-optimize/SKILL.md +86 -0
  34. package/skills/schema-migration/SKILL.md +119 -0
  35. package/skills/sql-review/SKILL.md +118 -0
  36. package/skills/sql-translate/SKILL.md +68 -0
  37. package/skills/teach/SKILL.md +54 -0
  38. package/skills/train/SKILL.md +51 -0
  39. package/skills/training-status/SKILL.md +45 -0
@@ -0,0 +1,394 @@
1
+ # Component Library Reference
2
+
3
+ Non-obvious patterns, gotchas, and custom implementations. Standard library usage (basic bar/line/area/pie/scatter) is well-documented — this covers what agents get wrong or can't infer.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [shadcn/ui Charts](#shadcnui-charts) — Config pattern & key rules
8
+ 2. [Tremor Essentials](#tremor-essentials) — KPI cards, dashboard grid
9
+ 3. [Nivo Gotchas](#nivo-gotchas) — Height wrapper, common props
10
+ 4. [D3 + React Pattern](#d3--react-pattern) — Force-directed DAG
11
+ 5. [Layout Patterns](#layout-patterns) — Dashboard grid, card component
12
+ 6. [Color Systems](#color-systems) — Semantic, sequential, diverging, categorical
13
+ 7. [Data Transformations](#data-transformations) — Recharts pivot, KPI aggregate, treemap, time bucketing
14
+ 8. [Waterfall Chart](#waterfall-chart) — Custom Recharts pattern
15
+ 9. [Radar / Spider Chart](#radar--spider-chart) — Key rules
16
+ 10. [Calendar Heatmap](#calendar-heatmap) — Nivo setup
17
+ 11. [Annotation Patterns](#annotation-patterns) — Goal lines, highlights, callouts, anomaly dots
18
+
19
+ ---
20
+
21
+ ## shadcn/ui Charts
22
+
23
+ Built on Recharts with themed, accessible wrappers. **Unique config pattern — don't skip this.**
24
+
25
+ ```tsx
26
+ import { type ChartConfig } from "@/components/ui/chart"
27
+
28
+ const chartConfig = {
29
+ revenue: { label: "Revenue", color: "hsl(var(--chart-1))" },
30
+ expenses: { label: "Expenses", color: "hsl(var(--chart-2))" },
31
+ } satisfies ChartConfig
32
+ ```
33
+
34
+ **Key rules:**
35
+ - Always `min-h-[VALUE]` on `ChartContainer` (required for responsiveness)
36
+ - Use `accessibilityLayer` prop on the main chart component
37
+ - Colors via CSS variables `var(--color-{key})`, never hardcoded
38
+ - Use `ChartTooltip` + `ChartTooltipContent`, not Recharts defaults
39
+ - Use `ChartLegend` + `ChartLegendContent` for interactive legends
40
+
41
+ ### Area Chart Gradient (common pattern)
42
+
43
+ ```tsx
44
+ <defs>
45
+ <linearGradient id="fillRevenue" x1="0" y1="0" x2="0" y2="1">
46
+ <stop offset="5%" stopColor="var(--color-revenue)" stopOpacity={0.8} />
47
+ <stop offset="95%" stopColor="var(--color-revenue)" stopOpacity={0.1} />
48
+ </linearGradient>
49
+ </defs>
50
+ <Area type="monotone" dataKey="revenue" stroke="var(--color-revenue)" fill="url(#fillRevenue)" />
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Tremor Essentials
56
+
57
+ ### KPI Card Pattern
58
+
59
+ ```tsx
60
+ import { Card, BadgeDelta, SparkAreaChart } from "@tremor/react"
61
+
62
+ <Card className="max-w-sm">
63
+ <div className="flex items-center justify-between">
64
+ <p className="text-tremor-default text-tremor-content">Revenue</p>
65
+ <BadgeDelta deltaType="increase" size="xs">+12.3%</BadgeDelta>
66
+ </div>
67
+ <p className="text-tremor-metric font-semibold mt-1">$1.24M</p>
68
+ <SparkAreaChart data={sparkData} categories={["value"]} index="date"
69
+ colors={["emerald"]} className="h-8 w-full mt-4" />
70
+ </Card>
71
+ ```
72
+
73
+ ### Dashboard Grid
74
+
75
+ ```tsx
76
+ <div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4">
77
+ {kpis.map(kpi => <KPICard key={kpi.id} {...kpi} />)}
78
+ </div>
79
+ ```
80
+
81
+ ### Tremor AreaChart / BarList
82
+
83
+ ```tsx
84
+ <AreaChart data={data} index="month" categories={["Revenue", "Expenses"]}
85
+ colors={["blue", "red"]} valueFormatter={(v) => `$${(v/1000).toFixed(0)}k`}
86
+ className="h-72 mt-4" showAnimation />
87
+
88
+ <BarList data={[{ name: "Google", value: 45632 }, ...]} className="mt-4" />
89
+ ```
90
+
91
+ ---
92
+
93
+ ## Nivo Gotchas
94
+
95
+ - **Always set `height` on the wrapper div**, not on the Nivo component: `<div style={{ height: 400 }}><ResponsiveHeatMap ... /></div>`
96
+ - Use `emptyColor="#f3f4f6"` for missing data cells
97
+ - For heatmaps: `colors={{ type: "sequential", scheme: "blues" }}`
98
+ - For treemaps: `identity="name"` + `value="value"` + `labelSkipSize={12}`
99
+ - For Sankey: `enableLinkGradient` + `linkBlendMode="multiply"` for polish
100
+ - For Choropleth: needs GeoJSON features, `projectionScale={150}`, `projectionTranslation={[0.5, 0.5]}`
101
+
102
+ ---
103
+
104
+ ## D3 + React Pattern: Force-Directed DAG
105
+
106
+ Use for lineage graphs, dependency trees, pipeline DAGs. **D3 computes positions, React renders SVG.**
107
+
108
+ ```tsx
109
+ import { useEffect, useRef } from "react"
110
+ import * as d3 from "d3"
111
+
112
+ interface DagNode { id: string; label: string; type: "source" | "middle" | "output" }
113
+ interface DagLink { source: string; target: string }
114
+
115
+ const NODE_COLORS: Record<DagNode["type"], { fill: string; stroke: string }> = {
116
+ source: { fill: "#dbeafe", stroke: "#3b82f6" },
117
+ middle: { fill: "#f1f5f9", stroke: "#94a3b8" },
118
+ output: { fill: "#dcfce7", stroke: "#22c55e" },
119
+ }
120
+
121
+ export function ForceDAG({ nodes, links }: { nodes: DagNode[]; links: DagLink[] }) {
122
+ const svgRef = useRef<SVGSVGElement>(null)
123
+
124
+ useEffect(() => {
125
+ if (!svgRef.current) return
126
+ const width = svgRef.current.clientWidth || 800, height = 500
127
+ const svg = d3.select(svgRef.current).attr("height", height)
128
+ svg.selectAll("*").remove()
129
+
130
+ // Arrowhead marker
131
+ svg.append("defs").append("marker")
132
+ .attr("id", "dag-arrow").attr("viewBox", "0 -5 10 10")
133
+ .attr("refX", 22).attr("refY", 0)
134
+ .attr("markerWidth", 6).attr("markerHeight", 6).attr("orient", "auto")
135
+ .append("path").attr("d", "M0,-5L10,0L0,5").attr("fill", "#94a3b8")
136
+
137
+ // CRITICAL: Copy arrays — D3 mutates them with x/y/vx/vy
138
+ const nodesCopy = nodes.map(n => ({ ...n }))
139
+ const linksCopy = links.map(l => ({ ...l }))
140
+
141
+ const sim = d3.forceSimulation(nodesCopy as any)
142
+ .force("link", d3.forceLink(linksCopy).id((d: any) => d.id).distance(140))
143
+ .force("charge", d3.forceManyBody().strength(-350))
144
+ .force("center", d3.forceCenter(width / 2, height / 2))
145
+ .force("collision", d3.forceCollide().radius(50))
146
+
147
+ const linkSel = svg.append("g").selectAll("line")
148
+ .data(linksCopy).join("line")
149
+ .attr("stroke", "#cbd5e1").attr("stroke-width", 1.5)
150
+ .attr("marker-end", "url(#dag-arrow)")
151
+
152
+ const nodeSel = svg.append("g").selectAll<SVGGElement, DagNode>("g")
153
+ .data(nodesCopy).join("g")
154
+ .call(d3.drag<SVGGElement, any>()
155
+ .on("start", (e, d) => { if (!e.active) sim.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y })
156
+ .on("drag", (e, d) => { d.fx = e.x; d.fy = e.y })
157
+ .on("end", (e, d) => { if (!e.active) sim.alphaTarget(0); d.fx = null; d.fy = null }))
158
+
159
+ nodeSel.append("rect").attr("x", -54).attr("y", -18)
160
+ .attr("width", 108).attr("height", 36).attr("rx", 6)
161
+ .attr("fill", (d: any) => NODE_COLORS[d.type].fill)
162
+ .attr("stroke", (d: any) => NODE_COLORS[d.type].stroke).attr("stroke-width", 1.5)
163
+
164
+ nodeSel.append("text").attr("text-anchor", "middle").attr("dy", "0.35em")
165
+ .attr("font-size", 11).attr("fill", "#374151")
166
+ .text((d: any) => d.label.length > 16 ? d.label.slice(0, 15) + "…" : d.label)
167
+
168
+ sim.on("tick", () => {
169
+ linkSel.attr("x1", (d: any) => d.source.x).attr("y1", (d: any) => d.source.y)
170
+ .attr("x2", (d: any) => d.target.x).attr("y2", (d: any) => d.target.y)
171
+ nodeSel.attr("transform", (d: any) => `translate(${d.x},${d.y})`)
172
+ })
173
+ return () => { sim.stop() }
174
+ }, [nodes, links])
175
+
176
+ return <svg ref={svgRef} className="w-full" style={{ minHeight: 500 }} />
177
+ }
178
+ ```
179
+
180
+ **Rules:** Always copy nodes/links before D3. Use `clientWidth` for responsive width. Truncate labels, show full on hover. `alphaTarget(0)` on drag end lets sim cool naturally.
181
+
182
+ ---
183
+
184
+ ## Layout Patterns
185
+
186
+ ### Dashboard Grid (Tailwind)
187
+
188
+ ```tsx
189
+ <div className="min-h-screen bg-background p-6">
190
+ <div className="mb-8 flex items-center justify-between">
191
+ <div>
192
+ <h1 className="text-2xl font-bold tracking-tight">Analytics</h1>
193
+ <p className="text-muted-foreground">Your performance overview</p>
194
+ </div>
195
+ <DateRangePicker />
196
+ </div>
197
+ <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4 mb-8">
198
+ {kpis.map(kpi => <KPICard key={kpi.id} {...kpi} />)}
199
+ </div>
200
+ <div className="grid gap-4 md:grid-cols-7 mb-8">
201
+ <Card className="col-span-4">{/* Primary chart */}</Card>
202
+ <Card className="col-span-3">{/* Secondary chart */}</Card>
203
+ </div>
204
+ <Card>{/* DataTable */}</Card>
205
+ </div>
206
+ ```
207
+
208
+ ### shadcn-style Card
209
+
210
+ ```tsx
211
+ <div className="rounded-xl border bg-card p-6 shadow-sm">
212
+ <div className="flex items-center justify-between">
213
+ <p className="text-sm font-medium text-muted-foreground">{title}</p>
214
+ <Icon className="h-4 w-4 text-muted-foreground" />
215
+ </div>
216
+ <div className="mt-2">
217
+ <p className="text-2xl font-bold">{value}</p>
218
+ <p className={cn("text-xs mt-1", delta > 0 ? "text-green-600" : "text-red-600")}>
219
+ {delta > 0 ? "+" : ""}{delta}% from last period
220
+ </p>
221
+ </div>
222
+ </div>
223
+ ```
224
+
225
+ ---
226
+
227
+ ## Color Systems
228
+
229
+ **Semantic (default):**
230
+ ```css
231
+ --chart-1: 221.2 83.2% 53.3%; /* Blue */
232
+ --chart-2: 142.1 76.2% 36.3%; /* Green */
233
+ --chart-3: 24.6 95% 53.1%; /* Orange */
234
+ --chart-4: 346.8 77.2% 49.8%; /* Red */
235
+ --chart-5: 262.1 83.3% 57.8%; /* Purple */
236
+ ```
237
+
238
+ **Sequential** (heatmaps/gradients): Single hue light→dark. Tailwind `blue-100`→`blue-900` or Nivo schemes: `blues`, `greens`, `oranges`.
239
+
240
+ **Diverging** (+/- values): Red ↔ White ↔ Green, or Red ↔ Grey ↔ Blue. Center on zero.
241
+
242
+ **Categorical** (distinct groups): Max 7. Tailwind `500` shades: `blue`, `emerald`, `amber`, `rose`, `violet`, `cyan`, `orange`.
243
+
244
+ ---
245
+
246
+ ## Data Transformations
247
+
248
+ ### Pivot for Recharts
249
+
250
+ Recharts needs flat arrays with all series as keys per data point:
251
+
252
+ ```ts
253
+ // { date, category, value } rows → { date, cat_A: val, cat_B: val }
254
+ const pivoted = _.chain(rawData).groupBy("date")
255
+ .map((items, date) => ({ date, ..._.fromPairs(items.map(i => [i.category, i.value])) }))
256
+ .value()
257
+ ```
258
+
259
+ ### KPI Aggregation
260
+
261
+ ```ts
262
+ const kpis = {
263
+ total: _.sumBy(data, "revenue"), average: _.meanBy(data, "revenue"),
264
+ max: _.maxBy(data, "revenue"), count: data.length,
265
+ growth: ((current - previous) / previous * 100).toFixed(1),
266
+ }
267
+ ```
268
+
269
+ ### Flat → Hierarchical (Treemaps)
270
+
271
+ ```ts
272
+ const tree = { name: "root", children: _.chain(data).groupBy("category")
273
+ .map((items, name) => ({ name, children: items.map(i => ({ name: i.label, value: i.amount })) })).value() }
274
+ ```
275
+
276
+ ### Time Bucketing
277
+
278
+ ```ts
279
+ import { format, startOfWeek } from "date-fns"
280
+ const weekly = _.chain(data).groupBy(d => format(startOfWeek(new Date(d.date)), "yyyy-MM-dd"))
281
+ .map((items, week) => ({ week, total: _.sumBy(items, "value"), count: items.length })).value()
282
+ ```
283
+
284
+ ---
285
+
286
+ ## Waterfall Chart
287
+
288
+ Recharts has no native waterfall. Use stacked Bar with invisible spacer:
289
+
290
+ ```tsx
291
+ function toWaterfallSeries(items: { name: string; value: number }[]) {
292
+ let running = 0
293
+ return items.map(item => {
294
+ const start = item.value >= 0 ? running : running + item.value
295
+ running += item.value
296
+ return { name: item.name, value: Math.abs(item.value), start, _raw: item.value }
297
+ })
298
+ }
299
+
300
+ // In ComposedChart:
301
+ <Bar dataKey="start" stackId="wf" fill="transparent" isAnimationActive={false} />
302
+ <Bar dataKey="value" stackId="wf" radius={[4,4,0,0]}>
303
+ {data.map((e, i) => <Cell key={i} fill={e._raw >= 0 ? "#22c55e" : "#ef4444"} />)}
304
+ </Bar>
305
+ ```
306
+
307
+ **Critical:** Spacer bar must have `isAnimationActive={false}` (animating it reveals the trick). Hide spacer from tooltip by returning `null` in formatter. For "total" bar: `start: 0`, `value: runningTotal`, distinct color (slate).
308
+
309
+ ---
310
+
311
+ ## Radar / Spider Chart
312
+
313
+ ```tsx
314
+ <RadarChart cx="50%" cy="50%" outerRadius="75%" data={data}>
315
+ <PolarGrid stroke="#e2e8f0" />
316
+ <PolarAngleAxis dataKey="dimension" tick={{ fontSize: 12, fill: "#64748b" }} />
317
+ <PolarRadiusAxis angle={90} domain={[0, 100]} tickCount={5} />
318
+ <Radar name="Current" dataKey="score" stroke="#6366f1" fill="#6366f1" fillOpacity={0.25} strokeWidth={2} />
319
+ <Radar name="Benchmark" dataKey="benchmark" stroke="#e2e8f0" fill="none" strokeDasharray="5 3" strokeWidth={1.5} />
320
+ <Tooltip /><Legend />
321
+ </RadarChart>
322
+ ```
323
+
324
+ **Rules:** `domain={[0, 100]}` for consistent comparison. Dashed benchmark gives context. Max 2 series.
325
+
326
+ ---
327
+
328
+ ## Calendar Heatmap
329
+
330
+ ```tsx
331
+ import { ResponsiveCalendar } from "@nivo/calendar"
332
+
333
+ <div style={{ height: 200 }}>
334
+ <ResponsiveCalendar data={data} from={from} to={to}
335
+ emptyColor="#f8fafc" colors={["#dbeafe", "#93c5fd", "#3b82f6", "#1d4ed8"]}
336
+ margin={{ top: 24, right: 20, bottom: 8, left: 20 }}
337
+ yearSpacing={40} dayBorderWidth={2} dayBorderColor="#ffffff" />
338
+ </div>
339
+ ```
340
+
341
+ **Rules:** Height on wrapper div, not component. Single-hue sequential palette. `emptyColor` near-white for sparse data.
342
+
343
+ ---
344
+
345
+ ## Annotation Patterns
346
+
347
+ Annotations turn charts into stories. **Limit 3 per chart.**
348
+
349
+ **Color by type:** amber `#f59e0b` = target/goal, red `#ef4444` = incident/risk, indigo `#6366f1` = event/release, green `#22c55e` = achievement.
350
+
351
+ ### Goal/Threshold Line
352
+
353
+ ```tsx
354
+ <ReferenceLine y={targetValue} stroke="#f59e0b" strokeDasharray="6 3" strokeWidth={1.5}
355
+ label={{ value: `Target: ${targetValue.toLocaleString()}`, position: "insideTopRight", fontSize: 11, fill: "#f59e0b" }} />
356
+ ```
357
+
358
+ ### Time Range Highlight
359
+
360
+ ```tsx
361
+ <ReferenceArea x1={start} x2={end} fill="#fee2e2" fillOpacity={0.5}
362
+ label={{ value: "Incident", position: "insideTopLeft", fontSize: 10, fill: "#ef4444" }} />
363
+ ```
364
+
365
+ ### Floating Callout Label
366
+
367
+ ```tsx
368
+ const CalloutLabel = ({ viewBox, label, color = "#1e293b" }: { viewBox?: { x: number; y: number }; label: string; color?: string }) => {
369
+ if (!viewBox) return null
370
+ const { x, y } = viewBox, w = label.length * 7 + 16
371
+ return (<g>
372
+ <rect x={x - w/2} y={y - 34} width={w} height={20} rx={4} fill={color} />
373
+ <text x={x} y={y - 20} textAnchor="middle" fontSize={11} fill="white" fontWeight={500}>{label}</text>
374
+ <line x1={x} y1={y - 14} x2={x} y2={y} stroke={color} strokeWidth={1} />
375
+ </g>)
376
+ }
377
+ // Usage: <ReferenceLine x={date} stroke="#6366f1" strokeDasharray="4 4" label={<CalloutLabel label="v2.0 shipped" color="#6366f1" />} />
378
+ ```
379
+
380
+ ### Anomaly Dot Highlight
381
+
382
+ ```tsx
383
+ <Line dataKey="value" strokeWidth={2} dot={(props) => {
384
+ const { cx, cy, payload, key } = props
385
+ if (!payload?.isAnomaly) return <circle key={key} cx={cx} cy={cy} r={3} fill="#6366f1" />
386
+ return (<g key={key}>
387
+ <circle cx={cx} cy={cy} r={10} fill="#ef4444" opacity={0.15} />
388
+ <circle cx={cx} cy={cy} r={4} fill="#ef4444" />
389
+ <text x={cx} y={cy - 14} textAnchor="middle" fontSize={11} fill="#ef4444">▲</text>
390
+ </g>)
391
+ }} />
392
+ ```
393
+
394
+ **Rules:** Never overlap data. Use `position: "insideTopRight"/"insideTopLeft"` on labels. Pair annotations with tooltips — annotation names the event, tooltip shows the value.
@@ -0,0 +1,130 @@
1
+ ---
2
+ name: dbt-analyze
3
+ description: Analyze downstream impact of dbt model changes using column-level lineage and the dependency graph. Use when evaluating the blast radius of a change before shipping. Powered by altimate-dbt.
4
+ ---
5
+
6
+ # dbt Impact Analysis
7
+
8
+ ## Requirements
9
+ **Agent:** any (read-only analysis)
10
+ **Tools used:** bash (runs `altimate-dbt` commands), read, glob, dbt_manifest, lineage_check, dbt_lineage, sql_analyze, altimate_core_extract_metadata
11
+
12
+ ## When to Use This Skill
13
+
14
+ **Use when the user wants to:**
15
+ - Understand what breaks if they change a model
16
+ - Evaluate downstream impact before shipping
17
+ - Find all consumers of a model or column
18
+ - Assess risk of a refactoring
19
+
20
+ **Do NOT use for:**
21
+ - Creating or fixing models → use `dbt-develop` or `dbt-troubleshoot`
22
+ - Adding tests → use `dbt-test`
23
+
24
+ ## Workflow
25
+
26
+ ### 1. Identify the Changed Model
27
+
28
+ Accept from the user, or auto-detect:
29
+ ```bash
30
+ # From git diff
31
+ git diff --name-only | grep '\.sql$'
32
+
33
+ # Or user provides a model name
34
+ altimate-dbt compile --model <name> # verify it exists
35
+ ```
36
+
37
+ ### 2. Map the Dependency Graph
38
+
39
+ ```bash
40
+ altimate-dbt children --model <name> # direct downstream
41
+ altimate-dbt parents --model <name> # what feeds it
42
+ ```
43
+
44
+ For the full downstream tree, recursively call `children` on each downstream model.
45
+
46
+ ### 3. Run Column-Level Lineage
47
+
48
+ **With manifest (preferred):** Use `dbt_lineage` to compute column-level lineage for a dbt model. This reads the manifest.json, extracts compiled SQL and upstream schemas, and traces column flow via the Rust engine. More accurate than raw SQL lineage because it resolves `ref()` and `source()` to actual schemas.
49
+
50
+ ```
51
+ dbt_lineage(model: <model_name>)
52
+ ```
53
+
54
+ **Without manifest (fallback):** Use `lineage_check` on the raw SQL to understand:
55
+ - Which source columns flow to which output columns
56
+ - Which columns were added, removed, or renamed
57
+
58
+ **Extract structural metadata:** Use `altimate_core_extract_metadata` on the SQL to get tables referenced, columns used, CTEs, subqueries — useful for mapping the full dependency surface.
59
+
60
+
61
+ ### 4. Cross-Reference with Downstream
62
+
63
+ For each downstream model:
64
+ 1. Read its SQL
65
+ 2. Check if it references any changed/removed columns
66
+ 3. Classify impact:
67
+
68
+ | Classification | Meaning | Action |
69
+ |---------------|---------|--------|
70
+ | **BREAKING** | Removed/renamed column used downstream | Must fix before shipping |
71
+ | **SAFE** | Added column, no downstream reference | Ship freely |
72
+ | **UNKNOWN** | Can't determine (dynamic SQL, macros) | Manual review needed |
73
+
74
+ ### 5. Generate Impact Report
75
+
76
+ ```
77
+ Impact Analysis: stg_orders
78
+ ════════════════════════════
79
+
80
+ Changed Model: stg_orders (materialized: view)
81
+ Columns: 5 → 6 (+1 added)
82
+ Removed: total_amount (renamed to order_total)
83
+
84
+ Downstream Impact (3 models):
85
+
86
+ Depth 1:
87
+ [BREAKING] int_order_metrics
88
+ Uses: total_amount → COLUMN RENAMED
89
+ Fix: Update column reference to order_total
90
+
91
+ [SAFE] int_order_summary
92
+ No references to changed columns
93
+
94
+ Depth 2:
95
+ [BREAKING] mart_revenue
96
+ Uses: total_amount via int_order_metrics → CASCADING
97
+ Fix: Verify after fixing int_order_metrics
98
+
99
+ Tests at Risk: 4
100
+ - not_null_stg_orders_order_total
101
+ - unique_int_order_metrics_order_id
102
+
103
+ Summary: 2 BREAKING, 1 SAFE
104
+ Recommended: Fix int_order_metrics first, then:
105
+ altimate-dbt build --model stg_orders --downstream
106
+ ```
107
+
108
+ ## Without Manifest (SQL-Only Mode)
109
+
110
+ If no manifest is available:
111
+ 1. Run `lineage_check` on the changed SQL
112
+ 2. Show column-level data flow
113
+ 3. Note: downstream impact requires a manifest
114
+ 4. Suggest: `altimate-dbt build-project` to generate one
115
+
116
+ ## Common Mistakes
117
+
118
+ | Mistake | Fix |
119
+ |---------|-----|
120
+ | Only checking direct children | Always trace the FULL downstream tree recursively |
121
+ | Ignoring test impacts | Check which tests reference changed columns |
122
+ | Shipping without building downstream | Always `altimate-dbt build --model <name> --downstream` |
123
+ | Not considering renamed columns | A rename is a break + add — downstream still references the old name |
124
+
125
+ ## Reference Guides
126
+
127
+ | Guide | Use When |
128
+ |-------|----------|
129
+ | [references/altimate-dbt-commands.md](references/altimate-dbt-commands.md) | Need the full CLI reference |
130
+ | [references/lineage-interpretation.md](references/lineage-interpretation.md) | Understanding lineage output |
@@ -0,0 +1,66 @@
1
+ # altimate-dbt Command Reference
2
+
3
+ All dbt operations use the `altimate-dbt` CLI. Output is JSON to stdout; logs go to stderr.
4
+
5
+ ```bash
6
+ altimate-dbt <command> [args...]
7
+ altimate-dbt <command> [args...] --format text # Human-readable output
8
+ ```
9
+
10
+ ## First-Time Setup
11
+
12
+ ```bash
13
+ altimate-dbt init # Auto-detect project root
14
+ altimate-dbt init --project-root /path # Explicit root
15
+ altimate-dbt init --python-path /path # Override Python
16
+ altimate-dbt doctor # Verify setup
17
+ altimate-dbt info # Project name, adapter, root
18
+ ```
19
+
20
+ ## Build & Run
21
+
22
+ ```bash
23
+ altimate-dbt build --model <name> [--downstream] # compile + run + test
24
+ altimate-dbt run --model <name> [--downstream] # materialize only
25
+ altimate-dbt test --model <name> # run tests only
26
+ altimate-dbt build-project # full project build
27
+ ```
28
+
29
+ ## Compile
30
+
31
+ ```bash
32
+ altimate-dbt compile --model <name>
33
+ altimate-dbt compile-query --query "SELECT * FROM {{ ref('stg_orders') }}" [--model <context>]
34
+ ```
35
+
36
+ ## Execute SQL
37
+
38
+ ```bash
39
+ altimate-dbt execute --query "SELECT count(*) FROM {{ ref('orders') }}" --limit 100
40
+ ```
41
+
42
+ ## Schema & DAG
43
+
44
+ ```bash
45
+ altimate-dbt columns --model <name> # column names and types
46
+ altimate-dbt columns-source --source <src> --table <tbl> # source table columns
47
+ altimate-dbt column-values --model <name> --column <col> # sample values
48
+ altimate-dbt children --model <name> # downstream models
49
+ altimate-dbt parents --model <name> # upstream models
50
+ ```
51
+
52
+ ## Packages
53
+
54
+ ```bash
55
+ altimate-dbt deps # install packages.yml
56
+ altimate-dbt add-packages --packages dbt-utils,dbt-expectations
57
+ ```
58
+
59
+ ## Error Handling
60
+
61
+ All errors return JSON with `error` and `fix` fields:
62
+ ```json
63
+ { "error": "dbt-core is not installed", "fix": "Install it: python3 -m pip install dbt-core" }
64
+ ```
65
+
66
+ Run `altimate-dbt doctor` as the first diagnostic step for any failure.
@@ -0,0 +1,58 @@
1
+ # Lineage Interpretation Guide
2
+
3
+ ## Understanding Column-Level Lineage
4
+
5
+ Column-level lineage traces how data flows from source columns through transformations to output columns.
6
+
7
+ ### Direct Lineage
8
+ ```
9
+ source.customers.name → stg_customers.customer_name → dim_customers.full_name
10
+ ```
11
+ Column was renamed at each step. A change to the source column affects all downstream.
12
+
13
+ ### Aggregation Lineage
14
+ ```
15
+ source.orders.amount → (SUM) → fct_daily_revenue.total_revenue
16
+ ```
17
+ Multiple source rows feed into one output value. The column type changes from row-level to aggregate.
18
+
19
+ ### Conditional Lineage
20
+ ```
21
+ source.orders.status → (CASE WHEN) → fct_orders.is_completed
22
+ ```
23
+ The source column feeds a derived boolean. The relationship is logical, not direct.
24
+
25
+ ## Impact Classification
26
+
27
+ ### BREAKING Changes
28
+ - **Column removed**: Downstream models referencing it will fail
29
+ - **Column renamed**: Same as removed — downstream still uses the old name
30
+ - **Type changed**: May cause cast errors or silent data loss downstream
31
+ - **Logic changed**: Downstream aggregations/filters may produce wrong results
32
+
33
+ ### SAFE Changes
34
+ - **Column added**: No downstream model can reference what didn't exist
35
+ - **Description changed**: No runtime impact
36
+ - **Test added/modified**: No impact on model data
37
+
38
+ ### REQUIRES REVIEW
39
+ - **Filter changed**: May change which rows appear → downstream counts change
40
+ - **JOIN type changed**: LEFT→INNER drops rows, INNER→LEFT adds NULLs
41
+ - **Materialization changed**: view→table has no logical impact but affects freshness
42
+
43
+ ## Reading the DAG
44
+
45
+ ```bash
46
+ altimate-dbt parents --model <name> # what this model depends on
47
+ altimate-dbt children --model <name> # what depends on this model
48
+ ```
49
+
50
+ A model with many children has high blast radius. A model with many parents has high complexity.
51
+
52
+ ## Depth Matters
53
+
54
+ - **Depth 1**: Direct consumers — highest risk, most likely to break
55
+ - **Depth 2+**: Cascading impact — will break IF depth 1 breaks
56
+ - **Depth 3+**: Usually only affected by breaking column removals/renames
57
+
58
+ Focus investigation on depth 1 first.