You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Module-level SQLAlchemy event.listen(Target, "event", fn) statements
are now extracted (the v1 KNOWN GAP) as family sqlalchemy_listen: fn
resolves to a first-party top-level function (same-module or imported
via the calls.py import tables, lifted to module level); the
registration attaches to the HANDLER's artifact (which may live in
another module) and grounds additionally on the registering file's
module span (new role registration_site) - wiring in a third module
grounds ONE artifact across THREE files. Module-level only (runs at
import time, confidence 1.0); function-body/lambda/bare-import forms
stay documented gaps. Call-form registrations sort before merging so
full and incremental indexing stay byte-identical.
events extractor_version 1 -> 2 (all event_handler ids recompute,
idempotent). Tier-1 events gate: known-gap test inverted + three-file
provenance + two new gap assertions (9 -> 12 tests). Gates stay
fifteen.
|`kb.introspect`| Eval-only runtime oracle: runs a FastAPI app in a network-blocked sandbox and emits `app.openapi()` for the Tier-1 API gate. Never on the index path. | subprocess sandbox, fastapi |
409
414
|`kb.embed`| Replaceable embedding adapters + snapshot population for `search_knowledge`. Torch isolated behind the `embed` extra and a lazy import. | sentence-transformers (default), OpenAI (optional), pgvector |
410
415
|`kb.rag`| Frozen pgvector RAG-over-source baseline — the "other arm" of the knowledge-vs-RAG A/B (no provenance/grounding). | deterministic line-window chunker, pgvector |
@@ -490,8 +495,9 @@ Review fact-checked these against current (2026) sources. Caveats are first-clas
490
495
491
496
1. Second deterministic family: **entities (pydantic/dataclass/SQLAlchemy) — shipped** (static
492
497
tree-sitter, hand-labeled Tier-1 gate); **events — shipped** (decorator registrations for
Copy file name to clipboardExpand all lines: README.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -87,7 +87,7 @@ flowchart LR
87
87
**v0.7 — spine (artifact-identity rule v2), six deterministic extractors (cross-file grounding, incl. the library public-API surface, event handlers, and call-graph edges) plus the grounded process-path builder over them, LLM-grounded descriptions up to whole-repo architecture overviews and business-process-path labels, ADR-candidate mining from git history (`kb mine`), live incremental re-index (`kb watch`), MCP serving, the fifteen knowledge gates, and published Docker images.** Everything here grounds what it claims, and nothing it cannot:
88
88
89
89
-**Provenance spine** — content-addressed `span_id` (LOCKED); tree-sitter spans with a normalized S-expression fingerprint and per-SHA location; a single-Postgres, Alembic-managed store with content-addressed idempotent writes; the ≥ 1 `derived_from` anti-hallucination invariant enforced in-app *and* by a deferred DB trigger; pygit2 git ingest (no checkout) with a diff-based invalidation seed.
90
-
- **Deterministic extractors** — the **import / dependency graph** (grimp resolves the edge, tree-sitter grounds it on the exact import statement, with an honest `approximate` fallback for re-exports / relative / unmappable imports — never a silent loss); the **FastAPI API-contract** extractor, which grounds a single route **across files** (handler in `routes.py` + `response_model` class in `schemas.py`); the **domain-entity** extractor (pydantic / dataclass / SQLAlchemy classes and their fields, grounded on the class definition **and cross-file on the entities they reference** — purely static, with documented detection limits); the **library public-API-surface** extractor (what a package exposes from its `__init__.py` — `__all__`-authoritative, with `__init__` re-exports resolved **cross-file** to the defining function/class — validated against an independent **griffe** static oracle); the **event-handler** extractor (pydantic `@field_validator`/`@model_validator`, FastAPI `@app.on_event`, SQLAlchemy `@event.listens_for` — one artifact per handler, grounded on the handler span and **cross-file** on the class it listens to; the call-form `event.listen(...)` and dynamic names are documented gaps); and the **call-graph edge** extractor (deterministic caller→callee edges — same-module, imported **cross-file**, and `self.` method calls — one `call_edge` per resolved pair with call-site lines aggregated; `obj.method(...)`, `getattr`, inherited self-calls and decorator/default-arg expressions are documented gaps; the deterministic foundation under the future business-process extractor); and the **process-path builder** (second-order: BFS over the call edges from extracted entrypoints — route/event handlers — to sink-registry matches, one `process_path` grounded on EVERY span of the chain, multi-file provenance; built-in sink registry + per-repo `.kb/sinks.yaml` override).
90
+
- **Deterministic extractors** — the **import / dependency graph** (grimp resolves the edge, tree-sitter grounds it on the exact import statement, with an honest `approximate` fallback for re-exports / relative / unmappable imports — never a silent loss); the **FastAPI API-contract** extractor, which grounds a single route **across files** (handler in `routes.py` + `response_model` class in `schemas.py`); the **domain-entity** extractor (pydantic / dataclass / SQLAlchemy classes and their fields, grounded on the class definition **and cross-file on the entities they reference** — purely static, with documented detection limits); the **library public-API-surface** extractor (what a package exposes from its `__init__.py` — `__all__`-authoritative, with `__init__` re-exports resolved **cross-file** to the defining function/class — validated against an independent **griffe** static oracle); the **event-handler** extractor (pydantic `@field_validator`/`@model_validator`, FastAPI `@app.on_event`, SQLAlchemy `@event.listens_for` **and the module-level call-form `event.listen(Target, "e", fn)`** — one artifact per handler, grounded on the handler span, **cross-file** on the class it listens to, and on the registering file for call-form wiring; function-body/lambda `listen` and dynamic names are documented gaps); and the **call-graph edge** extractor (deterministic caller→callee edges — same-module, imported **cross-file**, and `self.` method calls — one `call_edge` per resolved pair with call-site lines aggregated; `obj.method(...)`, `getattr`, inherited self-calls and decorator/default-arg expressions are documented gaps; the deterministic foundation under the future business-process extractor); and the **process-path builder** (second-order: BFS over the call edges from extracted entrypoints — route/event handlers — to sink-registry matches, one `process_path` grounded on EVERY span of the chain, multi-file provenance; built-in sink registry + per-repo `.kb/sinks.yaml` override).
91
91
-**`kb introspect`** — a sandboxed, network-blocked `app.openapi()` oracle, eval-only and never on the index path, that the API gate scores the static contract against.
92
92
-**Read-only MCP server** — `find_provenance`, `get_knowledge`, and `search_knowledge`, each returning provenance-carrying units (method + confidence + freshness).
93
93
-**pgvector embeddings + semantic search** — a replaceable embedding provider (sentence-transformers by default, OpenAI optional) populated by a separate `kb embed` pass; torch stays out of the index path.
@@ -244,7 +244,7 @@ A Python package `kb` (uv, src-layout). Modules and their responsibilities:
244
244
|`kb.extract.deterministic.library_surface`| Static library public-API-surface extractor — one `public_symbol` per name a package exposes from its `__init__.py` (`__all__`-authoritative), `__init__` re-exports resolved **cross-file** to the defining function/class; validated by an independent griffe static oracle. Never imports user code. |
245
245
|`kb.extract.deterministic.calls`| Static call-graph edge extractor — one `call_edge` per resolved caller→callee pair (same-module / imported **cross-file** / `self.` method), call-site lines aggregated; only resolved first-party edges are emitted; dynamic/attribute/inherited calls are documented gaps. Never imports user code. |
246
246
|`kb.extract.deterministic.paths`| Second-order process-path builder — `process_path` per (entrypoint, sink, terminal): shortest chain of resolved call edges from an extracted route/event handler to a sink-registry match, grounded on every span along the path (multi-file); built-in registry + `.kb/sinks.yaml` override (registry digest is identity-bearing); caps flagged, never silent. |
247
-
|`kb.extract.deterministic.events`| Static event-handler extractor — one `event_handler` per handler carrying pydantic validator / FastAPI `on_event` / SQLAlchemy `listens_for` decorator registrations (stacked decorators in `payload.registrations`), grounded on the handler span **and, across files, on the class it listens to**; call-form `event.listen(...)` and dynamic names are documented gaps. |
247
+
|`kb.extract.deterministic.events`| Static event-handler extractor — one `event_handler` per handler carrying pydantic validator / FastAPI `on_event` / SQLAlchemy `listens_for` decorator registrations **and module-level call-form `event.listen(...)` registrations** (all aggregated in `payload.registrations`; the handler may live in another module than the `listen()`), grounded on the handler span,**across files on the class it listens to**, and on the registering file's module span (role `registration_site`); function-body/lambda `listen` and dynamic names are documented gaps. |
248
248
|`kb.introspect`| Sandboxed, network-blocked `app.openapi()` oracle — eval-only ground truth for the API gate, never on the index path. |
249
249
|`kb.mcp`| Read-only MCP server and its provenance-carrying records: `find_provenance`, `get_knowledge`, `search_knowledge`. |
250
250
|`kb.embed`| Replaceable embedding adapters (sentence-transformers default, OpenAI optional) + snapshot population. Torch isolated behind the `embed` extra and a lazy import. |
4.**Tier-1 API oracle** — the statically-extracted FastAPI contract equals the app's own `openapi()` (from the sandboxed introspect oracle), and the route's cross-file grounding (handler + `response_model`) is asserted.
273
273
5.**Tier-1 entities oracle** — extracted pydantic / dataclass / SQLAlchemy entities + their fields match a hand-labeled oracle, each grounded on its class span; a bare declarative `Base` is correctly *not* an entity and a `create_model(...)` model is asserted as a *known* gap.
274
274
6.**Tier-1 library-surface oracle** — the statically-extracted public API surface of a package (`__all__`-authoritative, `__init__` re-exports resolved **cross-file**) equals an independent **griffe** static oracle; underscore-private names are excluded, and a third-party / dynamic-`__all__` re-export is grounded-but-flagged, asserted as a *known* gap.
275
-
7.**Tier-1 events oracle** — extracted event handlers (pydantic validators, FastAPI `on_event`, SQLAlchemy `listens_for`) match a hand-labeled oracle, each grounded on its handler span and **cross-file** on the class it listens to; the call-form `event.listen(...)` and a dynamic `@app.on_event(EVENT)` name are asserted as *known* gaps.
275
+
7.**Tier-1 events oracle** — extracted event handlers (pydantic validators, FastAPI `on_event`, SQLAlchemy `listens_for` and the module-level call-form `event.listen`) match a hand-labeled oracle, each grounded on its handler span and **cross-file** on the class it listens to; a call-form registration wired in a third module grounds ONE artifact across **three files** (handler + target class + registration site); `listen(...)` inside a function body, a lambda listener, and a dynamic `@app.on_event(EVENT)` name are asserted as *known* gaps.
276
276
8.**Tier-1 call-graph oracle** — extracted call edges match a hand-labeled oracle (same-module, cross-file imported — incl. aliases and module-attribute forms — `self.` method calls, and class instantiation), each grounded on the caller **and** callee def spans (cross-file); a mutually recursive pair yields two distinct artifacts (identity-v2 regression); `obj.method(...)`, `getattr`, inherited self-calls and decorator-expression calls are asserted as *known* gaps.
277
277
9.**Tier-3 knowledge-vs-RAG recall** — knowbase cross-file recall@k == 1.0 for every cross-file question (API contracts **and** domain entities: in each case one artifact already spans both files, so the floor is *structural*, independent of embedding quality); the RAG arm is reported but **never asserted**, so a model bump can't redden CI.
278
278
10.**Tier-4 one-hop invalidation** — a content diff invalidates *exactly* the artifacts whose grounding span changed (set-equality: no over-invalidation, no stale survivors); a version bump invalidates everything.
0 commit comments