• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

valksor / kvelmo / 23419412497

23 Mar 2026 02:30AM UTC coverage: 51.3% (-0.8%) from 52.116%
23419412497

push

github

k0d3r1s
Add intelligent orchestration features across conductor, quality, and web UI

18 features that make kvelmo's lifecycle orchestration smarter, safer,
and more observable. Covers the full stack: Go packages, socket RPCs,
and web frontend.

## Per-Phase Intelligence

- Per-phase agent specialization: Configure different agents per
  lifecycle phase via agent.phase_agent settings. The conductor resolves
  overrides and the worker pool matches jobs to workers by agent name,
  falling back to any available worker.

- Router-based adaptive progression: After each phase completes, a
  PhaseRouter evaluates the output and decides advance/retry/skip/
  rollback. DefaultRouter always advances; the interface enables custom
  routing strategies. Route decisions tracked in WorkUnit history.

- Per-phase guardrails: Configurable pre/post validation checks per
  phase. Built-in: require-spec (blocks implement without specs) and
  max-diff-size (warns on large diffs). Violations become structured
  findings with state rollback on blocking failures.

## Quality & Safety

- Hold-the-line quality gating: Findings classified as introduced vs
  pre-existing based on git diff hunk analysis. Only agent-introduced
  issues block progression; inherited tech debt reported as
  informational. Enabled by default.

- Slop detection: AI-specific code smell checker catches boilerplate
  phrases in comments, excessive comment-to-code ratio, redundant error
  wrapping, commented-out code, and ignored errors without justification.

- Secret redaction: Strips secrets (AWS keys, GitHub tokens, API keys,
  private keys, JWT) from content before sending to LLM APIs. Uses
  same detection patterns as SecretScanner. Invalid custom patterns
  logged at warn level.

- Multi-agent consensus: Dispatch same review prompt to N agents in
  parallel, deduplicate findings by file+line+rule proximity with
  DetectedBy attribution. Deterministic agent ordering for reproducible
  output.

## Automation
... (continued)

801 of 1350 branches covered (59.33%)

Branch coverage included in aggregate %.

833 of 2253 new or added lines in 39 files covered. (36.97%)

8 existing lines in 3 files now uncovered.

21965 of 43028 relevant lines covered (51.05%)

0.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

63.47
/pkg/codegraph/graph.go
1
package codegraph
2

3
import (
4
        "context"
5
        "database/sql"
6
        "fmt"
7
        "log/slog"
8
        "os"
9
        "path/filepath"
10
        "strings"
11

12
        _ "modernc.org/sqlite"
13
)
14

15
// Graph stores code symbols and relationships in SQLite.
16
type Graph struct {
17
        db      *sql.DB
18
        rootDir string
19
}
20

21
// Symbol represents a code symbol (function, type, interface, method).
22
type Symbol struct {
23
        ID      int64  `json:"id"`
24
        Name    string `json:"name"`
25
        Kind    string `json:"kind"` // "function", "type", "interface", "method", "const", "var"
26
        File    string `json:"file"`
27
        Line    int    `json:"line"`
28
        Package string `json:"package"`
29
}
30

31
// Edge represents a relationship between symbols.
32
type Edge struct {
33
        FromID   int64  `json:"from_id"`
34
        ToID     int64  `json:"to_id"`
35
        Relation string `json:"relation"` // "calls", "implements", "embeds", "references"
36
}
37

38
const schema = `
39
CREATE TABLE IF NOT EXISTS symbols (
40
    id INTEGER PRIMARY KEY AUTOINCREMENT,
41
    name TEXT NOT NULL,
42
    kind TEXT NOT NULL,
43
    file TEXT NOT NULL,
44
    line INTEGER NOT NULL,
45
    package TEXT NOT NULL
46
);
47
CREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name);
48
CREATE INDEX IF NOT EXISTS idx_symbols_file ON symbols(file);
49
CREATE INDEX IF NOT EXISTS idx_symbols_package ON symbols(package);
50

51
CREATE TABLE IF NOT EXISTS edges (
52
    from_id INTEGER NOT NULL REFERENCES symbols(id),
53
    to_id INTEGER NOT NULL REFERENCES symbols(id),
54
    relation TEXT NOT NULL
55
);
56
CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(from_id);
57
CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(to_id);
58
`
59

60
// New opens or creates a SQLite-backed code graph at dbPath.
61
func New(ctx context.Context, dbPath string) (*Graph, error) {
1✔
62
        if err := os.MkdirAll(filepath.Dir(dbPath), 0o755); err != nil {
1✔
NEW
63
                return nil, fmt.Errorf("create db directory: %w", err)
×
NEW
64
        }
×
65

66
        db, err := sql.Open("sqlite", dbPath)
1✔
67
        if err != nil {
1✔
NEW
68
                return nil, fmt.Errorf("open sqlite: %w", err)
×
NEW
69
        }
×
70

71
        // Enable WAL mode for better concurrent read performance.
72
        if _, err := db.ExecContext(ctx, "PRAGMA journal_mode=WAL"); err != nil {
1✔
NEW
73
                _ = db.Close()
×
NEW
74

×
NEW
75
                return nil, fmt.Errorf("set WAL mode: %w", err)
×
NEW
76
        }
×
77

78
        if _, err := db.ExecContext(ctx, schema); err != nil {
1✔
NEW
79
                _ = db.Close()
×
NEW
80

×
NEW
81
                return nil, fmt.Errorf("create schema: %w", err)
×
NEW
82
        }
×
83

84
        return &Graph{db: db}, nil
1✔
85
}
86

87
// Close closes the underlying database connection.
88
func (g *Graph) Close() error {
1✔
89
        if g.db == nil {
1✔
NEW
90
                return nil
×
NEW
91
        }
×
92

93
        return g.db.Close()
1✔
94
}
95

96
// IndexFile parses a single Go file and indexes its symbols and edges.
97
func (g *Graph) IndexFile(ctx context.Context, path string) error {
1✔
98
        absPath, err := filepath.Abs(path)
1✔
99
        if err != nil {
1✔
NEW
100
                return fmt.Errorf("abs path: %w", err)
×
NEW
101
        }
×
102

103
        // Compute relative path for storage if rootDir is set.
104
        storePath := absPath
1✔
105
        if g.rootDir != "" {
2✔
106
                if rel, relErr := filepath.Rel(g.rootDir, absPath); relErr == nil {
2✔
107
                        storePath = rel
1✔
108
                }
1✔
109
        }
110

111
        symbols, edges, err := parseGoFile(absPath)
1✔
112
        if err != nil {
1✔
NEW
113
                return fmt.Errorf("parse %s: %w", path, err)
×
NEW
114
        }
×
115

116
        tx, err := g.db.BeginTx(ctx, nil)
1✔
117
        if err != nil {
1✔
NEW
118
                return fmt.Errorf("begin tx: %w", err)
×
NEW
119
        }
×
120
        defer tx.Rollback() //nolint:errcheck // rollback after commit is harmless
1✔
121

1✔
122
        // Remove old symbols and edges for this file.
1✔
123
        if _, err := tx.ExecContext(ctx, "DELETE FROM edges WHERE from_id IN (SELECT id FROM symbols WHERE file = ?) OR to_id IN (SELECT id FROM symbols WHERE file = ?)", storePath, storePath); err != nil {
1✔
NEW
124
                return fmt.Errorf("delete old edges: %w", err)
×
NEW
125
        }
×
126
        if _, err := tx.ExecContext(ctx, "DELETE FROM symbols WHERE file = ?", storePath); err != nil {
1✔
NEW
127
                return fmt.Errorf("delete old symbols: %w", err)
×
NEW
128
        }
×
129

130
        // Insert symbols and build a name->id map for edge resolution.
131
        nameToID := make(map[string]int64)
1✔
132
        for i := range symbols {
2✔
133
                symbols[i].File = storePath
1✔
134
                res, err := tx.ExecContext(ctx,
1✔
135
                        "INSERT INTO symbols (name, kind, file, line, package) VALUES (?, ?, ?, ?, ?)",
1✔
136
                        symbols[i].Name, symbols[i].Kind, symbols[i].File, symbols[i].Line, symbols[i].Package,
1✔
137
                )
1✔
138
                if err != nil {
1✔
NEW
139
                        return fmt.Errorf("insert symbol %s: %w", symbols[i].Name, err)
×
NEW
140
                }
×
141
                id, _ := res.LastInsertId()
1✔
142
                symbols[i].ID = id
1✔
143
                nameToID[symbols[i].Name] = id
1✔
144
        }
145

146
        // Insert edges — resolve names to IDs within this file, or look up globally.
147
        for _, e := range edges {
2✔
148
                fromID, ok := nameToID[e.FromName]
1✔
149
                if !ok {
2✔
150
                        continue
1✔
151
                }
152

153
                toID, ok := nameToID[e.ToName]
1✔
154
                if !ok {
2✔
155
                        // Try to find the target symbol in the database (from other files).
1✔
156
                        row := tx.QueryRowContext(ctx, "SELECT id FROM symbols WHERE name = ? LIMIT 1", e.ToName)
1✔
157
                        if err := row.Scan(&toID); err != nil {
2✔
158
                                continue // Skip unresolved edges.
1✔
159
                        }
160
                }
161

NEW
162
                if _, err := tx.ExecContext(ctx,
×
NEW
163
                        "INSERT INTO edges (from_id, to_id, relation) VALUES (?, ?, ?)",
×
NEW
164
                        fromID, toID, e.Relation,
×
NEW
165
                ); err != nil {
×
NEW
166
                        return fmt.Errorf("insert edge: %w", err)
×
NEW
167
                }
×
168
        }
169

170
        return tx.Commit()
1✔
171
}
172

173
// IndexDirectory walks dir and indexes all .go files (excluding vendor, testdata).
174
func (g *Graph) IndexDirectory(ctx context.Context, dir string) error {
1✔
175
        absDir, err := filepath.Abs(dir)
1✔
176
        if err != nil {
1✔
NEW
177
                return fmt.Errorf("abs dir: %w", err)
×
NEW
178
        }
×
179
        g.rootDir = absDir
1✔
180

1✔
181
        var indexed int
1✔
182
        walkErr := filepath.WalkDir(absDir, func(path string, d os.DirEntry, walkDirErr error) error {
2✔
183
                if walkDirErr != nil {
1✔
NEW
184
                        slog.Debug("skipping inaccessible entry", "path", path, "error", walkDirErr)
×
NEW
185

×
NEW
186
                        return filepath.SkipDir
×
NEW
187
                }
×
188

189
                name := d.Name()
1✔
190

1✔
191
                // Skip common non-source directories.
1✔
192
                if d.IsDir() {
2✔
193
                        switch name {
1✔
NEW
194
                        case "vendor", "testdata", "node_modules", ".git":
×
NEW
195
                                return filepath.SkipDir
×
196
                        }
197

198
                        return nil
1✔
199
                }
200

201
                if !strings.HasSuffix(name, ".go") {
2✔
202
                        return nil
1✔
203
                }
1✔
204

205
                if err := g.IndexFile(ctx, path); err != nil {
1✔
NEW
206
                        slog.Debug("skipping file", "path", path, "error", err)
×
NEW
207

×
NEW
208
                        return nil
×
NEW
209
                }
×
210
                indexed++
1✔
211

1✔
212
                return nil
1✔
213
        })
214
        if walkErr != nil {
1✔
NEW
215
                return fmt.Errorf("walk directory: %w", walkErr)
×
NEW
216
        }
×
217

218
        slog.Info("code graph indexed", "dir", dir, "files", indexed)
1✔
219

1✔
220
        return nil
1✔
221
}
222

223
// QueryCallersOf finds symbols that call the given function name.
224
func (g *Graph) QueryCallersOf(ctx context.Context, name string) ([]Symbol, error) {
1✔
225
        rows, err := g.db.QueryContext(ctx, `
1✔
226
                SELECT s.id, s.name, s.kind, s.file, s.line, s.package
1✔
227
                FROM symbols s
1✔
228
                JOIN edges e ON e.from_id = s.id
1✔
229
                JOIN symbols target ON e.to_id = target.id
1✔
230
                WHERE target.name = ? AND e.relation = 'calls'
1✔
231
        `, name)
1✔
232
        if err != nil {
1✔
NEW
233
                return nil, fmt.Errorf("query callers: %w", err)
×
NEW
234
        }
×
235
        defer func() { _ = rows.Close() }()
2✔
236

237
        return scanSymbols(rows)
1✔
238
}
239

240
// QueryDependenciesOf finds packages imported by the given package.
NEW
241
func (g *Graph) QueryDependenciesOf(ctx context.Context, pkg string) ([]string, error) {
×
NEW
242
        rows, err := g.db.QueryContext(ctx, `
×
NEW
243
                SELECT DISTINCT target.package
×
NEW
244
                FROM symbols s
×
NEW
245
                JOIN edges e ON e.from_id = s.id
×
NEW
246
                JOIN symbols target ON e.to_id = target.id
×
NEW
247
                WHERE s.package = ? AND e.relation = 'imports'
×
NEW
248
        `, pkg)
×
NEW
249
        if err != nil {
×
NEW
250
                return nil, fmt.Errorf("query dependencies: %w", err)
×
NEW
251
        }
×
NEW
252
        defer func() { _ = rows.Close() }()
×
253

NEW
254
        var deps []string
×
NEW
255
        for rows.Next() {
×
NEW
256
                var dep string
×
NEW
257
                if err := rows.Scan(&dep); err != nil {
×
NEW
258
                        return nil, fmt.Errorf("scan dependency: %w", err)
×
NEW
259
                }
×
NEW
260
                deps = append(deps, dep)
×
261
        }
262

NEW
263
        return deps, rows.Err()
×
264
}
265

266
// QuerySymbol finds symbols matching the given name (exact match).
267
func (g *Graph) QuerySymbol(ctx context.Context, name string) ([]Symbol, error) {
1✔
268
        rows, err := g.db.QueryContext(ctx,
1✔
269
                "SELECT id, name, kind, file, line, package FROM symbols WHERE name = ?",
1✔
270
                name,
1✔
271
        )
1✔
272
        if err != nil {
1✔
NEW
273
                return nil, fmt.Errorf("query symbol: %w", err)
×
NEW
274
        }
×
275
        defer func() { _ = rows.Close() }()
2✔
276

277
        return scanSymbols(rows)
1✔
278
}
279

280
// QuerySymbolPattern finds symbols matching a LIKE pattern (use % for wildcards).
281
func (g *Graph) QuerySymbolPattern(ctx context.Context, pattern string) ([]Symbol, error) {
1✔
282
        rows, err := g.db.QueryContext(ctx,
1✔
283
                "SELECT id, name, kind, file, line, package FROM symbols WHERE name LIKE ?",
1✔
284
                pattern,
1✔
285
        )
1✔
286
        if err != nil {
1✔
NEW
287
                return nil, fmt.Errorf("query symbol pattern: %w", err)
×
NEW
288
        }
×
289
        defer func() { _ = rows.Close() }()
2✔
290

291
        return scanSymbols(rows)
1✔
292
}
293

294
// Stats returns counts of symbols and edges by kind/relation.
295
func (g *Graph) Stats(ctx context.Context) map[string]int {
1✔
296
        stats := make(map[string]int)
1✔
297

1✔
298
        // Total symbols.
1✔
299
        row := g.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM symbols")
1✔
300
        var count int
1✔
301
        if err := row.Scan(&count); err == nil {
2✔
302
                stats["symbols"] = count
1✔
303
        }
1✔
304

305
        // Symbols by kind.
306
        if err := g.collectGroupCounts(ctx, "SELECT kind, COUNT(*) FROM symbols GROUP BY kind", "symbols_", stats); err != nil {
1✔
NEW
307
                slog.Debug("stats: symbols by kind", "error", err)
×
NEW
308
        }
×
309

310
        // Total edges.
311
        row = g.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM edges")
1✔
312
        if err := row.Scan(&count); err == nil {
2✔
313
                stats["edges"] = count
1✔
314
        }
1✔
315

316
        // Edges by relation.
317
        if err := g.collectGroupCounts(ctx, "SELECT relation, COUNT(*) FROM edges GROUP BY relation", "edges_", stats); err != nil {
1✔
NEW
318
                slog.Debug("stats: edges by relation", "error", err)
×
NEW
319
        }
×
320

321
        // File count.
322
        row = g.db.QueryRowContext(ctx, "SELECT COUNT(DISTINCT file) FROM symbols")
1✔
323
        if err := row.Scan(&count); err == nil {
2✔
324
                stats["files"] = count
1✔
325
        }
1✔
326

327
        return stats
1✔
328
}
329

330
// collectGroupCounts runs a "SELECT label, COUNT(*)" query and stores results in stats with the given prefix.
331
func (g *Graph) collectGroupCounts(ctx context.Context, query, prefix string, stats map[string]int) error {
1✔
332
        rows, err := g.db.QueryContext(ctx, query)
1✔
333
        if err != nil {
1✔
NEW
334
                return fmt.Errorf("query: %w", err)
×
NEW
335
        }
×
336
        defer func() { _ = rows.Close() }()
2✔
337

338
        for rows.Next() {
2✔
339
                var label string
1✔
340
                var c int
1✔
341
                if err := rows.Scan(&label, &c); err == nil {
2✔
342
                        stats[prefix+label] = c
1✔
343
                }
1✔
344
        }
345

346
        return rows.Err()
1✔
347
}
348

349
func scanSymbols(rows *sql.Rows) ([]Symbol, error) {
1✔
350
        var symbols []Symbol
1✔
351
        for rows.Next() {
2✔
352
                var s Symbol
1✔
353
                if err := rows.Scan(&s.ID, &s.Name, &s.Kind, &s.File, &s.Line, &s.Package); err != nil {
1✔
NEW
354
                        return nil, fmt.Errorf("scan symbol: %w", err)
×
NEW
355
                }
×
356
                symbols = append(symbols, s)
1✔
357
        }
358

359
        return symbols, rows.Err()
1✔
360
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc