Skip to content

Commit cc9fae7

Browse files
committed
Better code quality
1 parent 2c369c3 commit cc9fae7

42 files changed

Lines changed: 5679 additions & 6064 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/rules/tldrgraph.md

Lines changed: 0 additions & 31 deletions
This file was deleted.

.githooks/pre-commit

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/usr/bin/env bash
2+
# Git pre-commit hook to verify code health rules and test integrity.
3+
4+
set -e
5+
6+
echo "🔍 Running TLDRGraph pre-commit code health check..."
7+
8+
# Run code health linter
9+
python3 scripts/check_code_health.py --target-dir tldrgraph
10+
11+
if [ $? -ne 0 ]; then
12+
echo "❌ Pre-commit check failed: Code quality limits exceeded."
13+
echo "Please ensure all files are < 400 lines and functions have complexity <= 15."
14+
exit 1
15+
fi
16+
17+
echo "✅ Code health check passed."

.tldrgraph/AGENT_CONTRACT.md

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
# TLDRGraph Agent Contract
2+
3+
**Audience: the coding agent with this repository open** (Claude Code, Cursor, Antigravity).
4+
5+
TLDRGraph builds an architectural graph from the graphify AST export. The layer set
6+
itself is designed by you, reading this repository. TLDRGraph ships no layer templates.
7+
Structure *within* a layer, and the high-volume deterministic seams between layers, are
8+
extracted automatically. What cannot be extracted automatically is:
9+
10+
- indirect dispatch, queue / event hops, dynamically-built routes;
11+
- the natural-language **intent** that makes semantic search work at all.
12+
13+
That is your job. You are not a fallback for a hosted model — you are the primary
14+
enrichment path, because **you can open the files**. The API path only ever sees a label
15+
and a path (`snippet` is never populated), so it guesses. You do not have to guess.
16+
17+
---
18+
19+
## Start here: `tldrgraph init`
20+
21+
One command does everything, and it is resumable:
22+
23+
```bash
24+
tldrgraph init
25+
```
26+
27+
It runs every deterministic step — extraction, classification, indexing, applying whatever
28+
you last wrote — then stops with a `NEXT ACTION` block the moment it needs judgement only
29+
you can supply. Do what the block says and run it again. Repeat until `status: done`.
30+
31+
| status | what it wants |
32+
| --- | --- |
33+
| `needs_layers` | Read the code and design this repository's architecture. **TLDRGraph ships no layer templates**; nothing will be applied for you. The request carries sketches of how other kinds of codebase divide — for shape only, never to copy. |
34+
| `needs_confirmation` | Enrichment costs the user tokens. Show them the estimate and ask. Then `tldrgraph init --yes`. |
35+
| `needs_enrichment` | A batch to open, read and describe, per the schema below. |
36+
| `done` | Nothing left. Use `query` / `trace` / `layers`. |
37+
38+
`--json` gives you the same thing machine-readably. The sections below document the file
39+
formats `init` reads and writes; the underlying `queue-enrichment` / `apply-enrichment`
40+
commands remain available for scripting.
41+
42+
**Copy every `id` verbatim from the request.** A constructed id matches nothing, is
43+
dropped, and will be reported back to you — but the work is wasted.
44+
45+
---
46+
47+
## The loop
48+
49+
```bash
50+
tldrgraph queue-enrichment --limit 50 # 1. writes .tldrgraph/enrichment_request.yaml
51+
# 2. you read it, read the SOURCE, and write
52+
# .tldrgraph/enrichment_response.yaml
53+
tldrgraph apply-enrichment # 3. merges into the graph, cache and index
54+
tldrgraph queue-enrichment --limit 50 # 4. repeat -- the queue advances automatically
55+
```
56+
57+
Request and response are **separate files**. Never write your answer back into
58+
`enrichment_request.yaml`; it is regenerated on every run and your work would be lost.
59+
60+
| File | Written by | Read by |
61+
| --- | --- | --- |
62+
| `.tldrgraph/enrichment_request.yaml` (or `enrichment_request.json`) | `queue-enrichment` | you |
63+
| `.tldrgraph/enrichment_response.yaml` (or `enrichment_response.json`) | **you** | `apply-enrichment` |
64+
| `.tldrgraph/enrichment_cursor.json` | both commands | both commands |
65+
| `.tldrgraph/pending_enrichment.json` | *(legacy)* | `apply-enrichment`, only if no response file exists |
66+
67+
---
68+
69+
## Request schema (`enrichment_request.yaml`)
70+
71+
```yaml
72+
schema: codechakra/enrichment-request@1
73+
generated_at: "2026-08-19T00:00:00+00:00"
74+
response_file: .tldrgraph/enrichment_response.yaml
75+
contract: .tldrgraph/AGENT_CONTRACT.md
76+
progress:
77+
total_candidates: 1873 # un-enriched, non-utility nodes
78+
already_enriched: 12 # nodes that already carry an intent
79+
queued_now: 50 # entries in "nodes" below
80+
remaining_after: 1823 # still waiting after this batch is applied
81+
nodes:
82+
- id: backend_src_applications_applications_controller_applicationscontroller
83+
label: ApplicationsController
84+
layer_id: api
85+
layer: "Layer 2: API Gateway"
86+
file: backend/src/applications/applications.controller.ts
87+
source_location: L31
88+
degree: 41 # in + out edges in the AST graph
89+
cross_layer_degree: 17 # of those, how many cross a layer boundary
90+
rank: 1 # 1 = highest priority in this batch
91+
existing_intent_source: heuristic # "" when the node has no intent at all
92+
```
93+
94+
`file` is repo-relative. `source_location` is graphify's line hint and may be `null`.
95+
`layer_id` is the stable machine key (e.g. `cli`, `engine`, `storage`, `api`, `ui`).
96+
97+
`existing_intent_source` is `"heuristic"` when the node already carries an intent written
98+
by the offline template enricher. That text was generated from the label and layer alone
99+
— it has not read a line of source — so the node is still a candidate and your answer
100+
should overwrite it. Applied answers are stamped `"agent"` and are never re-queued.
101+
102+
---
103+
104+
## Response schema (`enrichment_response.yaml` or `enrichment_response.json`)
105+
106+
A **YAML list** (preferred) or **JSON array** of objects:
107+
108+
```yaml
109+
- id: backend_src_applications_applications_controller_applicationscontroller
110+
intent: |
111+
### Pension Application Lifecycle Gateway
112+
REST gateway for the pension application lifecycle. Authorizes DEO/AAO/AO/DAG roles,
113+
dispatches cases to ApplicationsService and records status transitions.
114+
input_fields:
115+
- caseId
116+
- transitionPayload
117+
- remarks
118+
- sanctionOrderNo
119+
output_fields:
120+
- applicationStatus
121+
- disposition
122+
calls:
123+
- ApplicationsService
124+
- JwtAuthGuard
125+
- RolesGuard
126+
- pension_cases
127+
```
128+
129+
Equivalent JSON format (also accepted from `.tldrgraph/enrichment_response.json` or `.tldrgraph/pending_enrichment.json`):
130+
```json
131+
[
132+
{
133+
"id": "backend_src_applications_applications_controller_applicationscontroller",
134+
"intent": "### Pension Application Lifecycle Gateway\nREST gateway for the pension application lifecycle.",
135+
"input_fields": ["caseId", "transitionPayload", "remarks", "sanctionOrderNo"],
136+
"output_fields": ["applicationStatus", "disposition"],
137+
"calls": ["ApplicationsService", "JwtAuthGuard", "RolesGuard", "pension_cases"]
138+
}
139+
]
140+
```
141+
142+
| Key | Type | Meaning |
143+
| --- | --- | --- |
144+
| `id` | string, **required** | The node id, copied **verbatim** from the request. An id that is not in the graph is skipped silently. |
145+
| `intent` | string (Markdown) | Markdown formatted explanation: what this symbol does, its role, and why it exists. AI decides how much depth is needed. This is the text semantic search matches against. |
146+
| `input_fields` | array of strings | Input parameters, arguments, request body payload attributes, query filters. |
147+
| `output_fields` | array of strings | Return types, response models, emitted event names, or mutated state attributes. |
148+
| `fields` | array of strings (legacy) | Supported for backwards compatibility (maps to input fields). |
149+
| `calls` | array of strings or objects | Downstream symbols, files (`file:symbol`), or node IDs this symbol calls. Cross-layer bridges are created with 100% confidence. |
150+
| `layer_id` | string (optional) | Explicitly reassign the architectural layer ID if the AST classification miscategorized it. |
151+
152+
`input_fields`, `output_fields`, and `calls` may be omitted or empty. An object with only `id` and `intent` is
153+
valid and useful.
154+
155+
---
156+
157+
## Hard rules
158+
159+
1. **Open and read the actual source file before writing an intent.** You have the repo
160+
checked out; that is the entire reason this path exists. Read `file` (use
161+
`source_location` to find the symbol), and read enough of its imports and callees to
162+
describe what it really does. An intent paraphrased from the label is worse than no
163+
intent, because it poisons search with confident-sounding noise.
164+
165+
2. **Do not invent fields or calls. Omit what you cannot verify in the code.** If you
166+
read the file and it handles three params, list three. Do not pad the list with what a
167+
symbol of that name "usually" has. `"fields": []` is a correct, honest answer.
168+
A wrong `calls` entry creates a real, wrong edge in the graph that later queries will
169+
follow.
170+
171+
3. **`calls` entries are resolved with 2-tier high precision.**
172+
- **Tier 1 (Exact Match, 100% confidence):** Exact symbol names (`ApplicationsService`),
173+
function names, node IDs, file paths (`calc.ts`), or database table names (`pension_cases`).
174+
- **Tier 2 (Vector Fallback):** Semantic search with a calibrated 0.35 score floor.
175+
176+
| Good | Bad |
177+
| --- | --- |
178+
| `ApplicationsService` | `the application service` |
179+
| `calc.ts` | `some calculation helper` |
180+
| `pension_cases` | `the database` |
181+
| `JwtAuthGuard` | `auth stuff` |
182+
183+
Prefer the exact symbol name, file name, or table/model name as it appears in the source.
184+
185+
4. **Copy `id` verbatim.** Do not normalize, shorten or re-case it.
186+
187+
5. **Answer only the nodes in the request.** Extra ids are ignored; missing ids just come
188+
back in a later batch.
189+
190+
---
191+
192+
## Priority order in the queue
193+
194+
The queue is not arbitrary — a node that many things depend on is worth more of your
195+
attention than a leaf. A node is a **candidate** when it sits outside `General / Utility`
196+
and either has no intent at all, or has one that came from the offline template heuristic
197+
(`enrichment_source: "heuristic"`, i.e. nobody read the source). Candidates are sorted by:
198+
199+
1. **`cross_layer_degree` descending** — neighbours that sit in a *different* layer.
200+
These are the seams TLDRGraph exists to describe, and they are exactly where the AST
201+
alone is weakest.
202+
2. **`degree` descending** — total in + out edges. Hub nodes first.
203+
3. **node id ascending** — only to make the ordering deterministic.
204+
205+
Both degrees are computed from the live graph. (The `degree` key that graphify emits is
206+
absent, so anything reading `node["degree"]` from the raw export sees `0`; TLDRGraph
207+
recomputes it and stamps it back into `.tldrgraph/graph.json`.)
208+
209+
---
210+
211+
## Paging and progress
212+
213+
`queue-enrichment` remembers what it has handed out in `.tldrgraph/enrichment_cursor.json`:
214+
215+
- `applied` — ids successfully merged by `apply-enrichment`. Never re-queued.
216+
- `queued` — ids handed out but not yet applied ("in flight"). Skipped by default.
217+
218+
So running `queue-enrichment` twice in a row **advances** to the next batch instead of
219+
repeating. Two escape hatches:
220+
221+
- `--requeue` — also hand out in-flight ids again (use when a batch was abandoned).
222+
- `--reset` — clear all progress and start again from the highest-priority node.
223+
- `--limit 0` — no cap; queue every remaining candidate at once.
224+
225+
---
226+
227+
## What `apply-enrichment` does with your answer
228+
229+
For each object it can match to a node:
230+
231+
1. sets `intent`, rewrites `summary` to `"<layer>: <label> - <intent>"`, sets `fields`;
232+
2. writes the node into the SQLite hash-gate cache, keyed by a content signature, so the
233+
work survives re-scans and is not redone until the file actually changes;
234+
3. resolves every `calls` entry through the vector index and, above the `0.35` floor,
235+
adds a `cross_layer_link` edge;
236+
4. re-indexes and persists `.tldrgraph/graph.json` plus `.tldrgraph/layers.yaml`.
237+
238+
It then records the ids in the cursor so the next `queue-enrichment` moves on.
239+
240+
---
241+
242+
## Related commands
243+
244+
```bash
245+
tldrgraph init # everything, resumable (scan/enrich are aliases)
246+
tldrgraph query "pension approval" # semantic search + end-to-end flow trace
247+
tldrgraph trace AaoDeskView pension_cases
248+
tldrgraph layers # node counts per layer
249+
tldrgraph dead-code --status candidate # nodes worth a human/agent review
250+
```
251+
252+
`query`, `trace`, `layers` and `dead-code` are read commands: they never trigger
253+
enrichment.
254+
255+
### `dead-code` is a review list, not a delete list
256+
257+
`dead-code` reports `dead_code_status` per node:
258+
259+
| Status | Means |
260+
| --- | --- |
261+
| `live` | Reached by something. |
262+
| `entry_point` | A root: route handler, CLI entry, cron job, exported public API. |
263+
| `candidate` | **Worth reviewing.** Nothing observed reaches it — which is evidence, not proof. |
264+
| `unreviewed` | **Not enough evidence to conclude anything.** Never treat as removable. |
265+
266+
TLDRGraph has no delete capability and will not gain one. Reflection, DI containers,
267+
string-built routes, template references and test-only entry points all produce nodes the
268+
static graph cannot see. Confirm with the source before removing anything.

.tldrgraph/layers.config.yaml

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
version: 1
2+
utility_id: utility
3+
layers:
4+
- id: cli
5+
name: 'Layer 1: CLI & Agent Surface'
6+
order: 1
7+
description: Command-line entry points, Click commands, agent loops, and installer
8+
contracts.
9+
rules:
10+
- file_contains:
11+
- cli.py
12+
- cli_commands.py
13+
- cli_agent_loop.py
14+
- cli_enrichment.py
15+
- agent_runner.py
16+
- installer.py
17+
- installer_contract.py
18+
- agent_commands.py
19+
- id: pipeline
20+
name: 'Layer 2: Pipeline & Ingestion'
21+
order: 2
22+
description: Graph build pipeline, AST ingestion from graphify, node registration,
23+
and snapshot synchronization.
24+
rules:
25+
- file_contains:
26+
- graph_loader.py
27+
- node_registrar.py
28+
- snapshot_sync.py
29+
- cli_pipeline.py
30+
- id: engine
31+
name: 'Layer 3: Analysis & Extraction Engine'
32+
order: 3
33+
description: Flow engine, multi-layer hierarchy builder, deterministic cross-layer
34+
extractors, dead-code analysis, and classifier.
35+
rules:
36+
- file_contains:
37+
- flow_engine.py
38+
- flow_traversal.py
39+
- hierarchy.py
40+
- hierarchy_builder.py
41+
- extractors
42+
- deadcode.py
43+
- labels.py
44+
- classifier.py
45+
- propose_layers.py
46+
- id: retrieval
47+
name: 'Layer 4: Vector Index & Retrieval'
48+
order: 4
49+
description: Local hybrid vector store, dense embeddings, TF-IDF sparse index, hash-gated
50+
cache, and call resolution.
51+
rules:
52+
- file_contains:
53+
- vector_store.py
54+
- vector_tfidf.py
55+
- dense_embedder.py
56+
- hash_gate.py
57+
- call_resolver.py
58+
- id: visualizer
59+
name: 'Layer 5: Visualization & Web UI'
60+
order: 5
61+
description: Interactive HTML graph visualizer, canvas rendering, data extraction,
62+
and live source view server.
63+
rules:
64+
- file_contains:
65+
- visualizer
66+
- render.py
67+
- palette.py
68+
- source.py
69+
- app.js
70+
- sourceview.js
71+
- id: utility
72+
name: 'Layer 6: Core Types & Utilities'
73+
order: 6
74+
description: Layer registry definitions, rule engines, path helpers, evidence detection,
75+
and shared utilities.

0 commit comments

Comments
 (0)