Blog 15 — v0.7.0: Static Scan Quality

PR: feat/v0.7.0-static-scan-quality
Date: 2026-06-18


The Previous Goalpost

At the end of PR #47 (v0.6.1), synlynk had a solid execution harness: context injection from project-docs/, sentinel detection, cost tracking, job dispatch, and a full capability scoring engine backed by SQLite WAL. But every synlynk exec session started with zero visibility into the source code of the repo it was operating on. Agents knew what tasks were active and what the roadmap said — they had no idea what modules, public symbols, or entry points existed in the actual codebase.

The Shift

This PR was fully driven by the brainstorm session of 2026-06-17 where we designed Static Scan Quality as the third of four initiative tracks. The design decision that most shaped the implementation was dual storage: SQLite source_symbols table as the primary structured store (queryable, future Tokq-sync-ready) plus project-docs/source-map.md as a materialized flat-file export (cloneable by any collaborator without running tooling). A third layer — scan-meta.json — serves as a hot skeleton cache keyed on git rev-parse HEAD.

What Shipped

v0.7.0 — Source Architecture in Every Exec Context

Symbol extraction engine

A regex-based per-language symbol extractor covering 9 languages (Python, JavaScript, TypeScript, Go, Rust, Ruby, Java, Kotlin, Shell) plus a generic fallback. Each file is read at most 300 lines. Language is detected from extension via _SOURCE_EXTENSIONS. Patterns are compiled regexes in _SYMBOL_PATTERNS — the first match per line wins. Shell coverage handles both name() and function name() syntax.

Symbol types recorded: function, async_function, class, interface, struct, trait, enum, type, constant, module.

File prioritization scoring

_score_source_files() walks the tree and scores every source file:

  • +3 for known entry-point filenames (main.py, index.ts, main.go, etc.) or cmd/main.go
  • +1 per appearance in the last 50 git commits (git log --name-only --pretty=format: -50)
  • −1 per directory level beyond depth 2

Top 15 by score are surfaced in the skeleton. Ties broken by path ascending.

Passive HEAD-keyed cache

_check_scan_cache() is called inside generate_context() on every synlynk exec and checkpoint. It compares git rev-parse HEAD against the SHA stored in .synlynk/scan-meta.json. On match: return cached skeleton instantly. On mismatch: call _scan_source_skeleton(), update scan-meta.json, return fresh result. No DB writes on the passive path — those only happen on --deep.

Context injection

generate_context() now writes a ## Source Architecture section between Active Tasks and Roadmap (active). Format:

## Source Architecture
_Scanned: 2026-06-18T14:22 · HEAD: abc1234 · 15 files · cache hit_

### src/auth/  [typescript · 2 files]
`src/auth/service.ts` — AuthService, verifyToken(), hashPassword()
`src/auth/models.ts` — User, Role

### [root]  [python · 1 file]
`manage.py` — main()

> 9 more files in source-map.md — run `synlynk scan --deep` to refresh
---

CLI surface

synlynk scan              # force-refresh skeleton
synlynk scan --deep       # full tree → state.db + project-docs/source-map.md
synlynk scan --status     # show cache age, HEAD SHA, file/symbol counts

Dual storage

synlynk scan --deep does a full tree walk, bulk-inserts all extracted symbols into state.db:source_symbols (with DELETE WHERE head_sha != current for single-SHA retention), and materialises project-docs/source-map.md with full symbol lists including line numbers and type annotations. The SQLite table has indexes on head_sha and file for future Tokq-sync queries.

_SCAN_SKIP_DIRS extended

Added: venv, env, vendor, .worktrees, coverage, .nyc_output, target, out, tmp.

Test coverage

New test file tests/test_static_scan.py with 41 tests covering all layers: per-language symbol extraction, 300-line boundary, file scoring and depth penalty, cache hit/miss, context injection ordering, source-map format, DB population, stale row clearing, and CLI output.

What Is Achieved

Every synlynk exec session now starts with structural knowledge of the repository — without AI calls, without build tools, without breaking the stdlib-only single-file constraint. The passive cache means there is zero overhead on cache-hit executions. Signal types A (structural) and D (change surface via git activity) are implemented; B (import graph) and C (vocabulary) remain future work as designed.

New Goalpost

v0.7.0 completes the source-intelligence layer. The next initiative is Capability Dogfood — using synlynk to dispatch real tasks to agents and accumulate live capability ledger data in state.db to validate the scoring engine against real-world outcomes.