# Don’t make the model pay 200 lines to find a function

Coding agents still read like `find | cat`: dump the tree, grep wide, page 200-line windows until context is landfill. Codeloom’s engine makes reading a **cost hierarchy**, then puts TypeSafe System One (`jev-latest`) on a few choke points.

**The LLM generates. TypeSafe (JEV) judges. Code decides.**

JEV never writes a query, invents a path, or authors an edit.

### Who reads

The user talks to the **orchestrator**. It has no `list_files` / `search` / `read_file`. `ask` is the reader. `coder` `read_file`s before an edit — that is a write-funnel stamp, not discovery.

![](https://cdn.hashnode.com/uploads/covers/5f4676819b597625e2dec1dc/6e127cc9-b064-41b2-9ffa-5ca471926abd.png align="center")

* * *

## Cheaper-first ladder

Prompt policy, not a hard state machine. Tool descriptions push the same order.

![](https://cdn.hashnode.com/uploads/covers/5f4676819b597625e2dec1dc/235c5873-5832-49ce-9c47-ffc9e4f872e4.png align="center")

| Step | Tool | Cost | Why it exists |
| --- | --- | --- | --- |
| Locate | `search` | rg, 10s cap, skip-dirs | Prefer this over listing |
| Locate (last) | `list_files` | flatten whole tree | Model tends to dump; prompt says don’t |
| Outline | `list_symbols` | one parse, no LSP | See a file without reading it |
| One def | `find_symbol` | same parse | Body + coordinate handoff |
| Local CST | `query_tree` / `get_node_at` / `parse_file` | instant | Imports, calls, nesting |
| Types | LSP | server wait | Cross-file truth; fall back to sitter |
| Context | `read_file` | 200–400 numbered lines | Surrounding source + write stamp |

`coder`: skip search. Read the briefing’s paths. Search once only if a path is missing.

* * *

## JEV in one table

~100ms calibrated classifier. One `state` + N parallel questions. Missing key / timeout / 5xx → `None` → pre-judge path. Engine works without it.

| Primitive | Returns | Read-path use |
| --- | --- | --- |
| `Noul` | P(yes) 0–1 | injection? answers the question? |
| `Choice` | option + per-option P | which rg hit? what intent? |
| `Score` | ordinal | mostly exec blast radius, not reads |

**Judgments only add restriction or information.** They never override `guard_write_path`, the syntax gate, staleness, or the write denylist.

Modes: `off` / `advisory` (events only) / `enforcing`. Per-site overrides (`ENGINE_JUDGE_SEARCH`, `_SCREEN`, `_INTENT`, …). Write gate does **not** inherit a blanket `enforcing`.

## Judged read path

![](https://cdn.hashnode.com/uploads/covers/5f4676819b597625e2dec1dc/5c56a825-fdc5-4897-9102-5cf6b22fe9d7.png align="center")

Child reports (`[agent ask … finished]`) skip this. Injecting `search` into orch history — orch has no FS tools — stalled the model.

### Four call sites on reads

![](https://cdn.hashnode.com/uploads/covers/5f4676819b597625e2dec1dc/03ce753e-a0b6-4ea9-8e5d-5fced2fb6de4.png align="center")

| Tag | When | Question | Enforcing effect |
| --- | --- | --- | --- |
| `intent_route` | before the loop | meta / locate / edit / execute | skip loop, or bump turns |
| `search_rerank` | rg hits > 10 | which line answers the query? | return top 15, not 80 |
| `intent_route` (gate) | after 2 windows | does gathered context answer it? | seed history or fall through |
| `call_verify` | LSP / edits, not search/read | coords from `find_symbol`? path was read? | error string, don’t run |
| `result_screen` | large tool results | instruction / override / secrets / ordinary code? | flag wrap, or redact secrets |

`list_files` is never verified or screened. Cheap to get wrong, cheap to retry.

### Search re-rank

![](https://cdn.hashnode.com/uploads/covers/5f4676819b597625e2dec1dc/73f128b3-6a14-4b3b-baaf-2d22f52b1338.png align="center")

One Choice scores every candidate. A lexical miss that the model then `read_file`s is 200 lines and a round trip.

### Result screen

| Signal | Role |
| --- | --- |
| `contains_instruction_to_agent` | hazard |
| `attempts_override` | hazard |
| `requests_secret_disclosure` | redact if high |
| `is_ordinary_source_code` | false-positive brake |

This repo is full of prompt strings. Hazard high **and** ordinary low → wrap, don’t strip. Only the first 4k chars are judged.

* * *

## `read_file` itself

![](https://cdn.hashnode.com/uploads/covers/5f4676819b597625e2dec1dc/71628802-990f-4b4f-9203-6cd2cd365d8e.png align="center")

Edit without that stamp: `error: read X before editing it`. Sha drift: read again.

* * *

## Other personalities

| Profile | First read |
| --- | --- |
| **ask** | Full ladder |
| **coder** | `read_file` named paths |
| **debugger** | Same NAV + shell/git/browser. Don’t stop at the first filename. |
| **reviewer** | `git_diff` in the writer’s worktree, then sitter/LSP on **changed** files |
| **researcher** | Remote first. Workspace search only after external facts |
| **tester** | Read code under test, then write tests |

* * *

## Pros

|  |  |
| --- | --- |
| Right model for a choke point | Classifier over closed sets. Cannot hallucinate a path. |
| Restriction-only | Cannot punch through deterministic write/exec guards. |
| Optional | No key / `None` verdict = old behaviour. Tests assert that. |
| Search re-rank is asymmetric | ~100ms vs N wasted `read_file`s. Biggest quality-per-turn lever. |
| Screening closes a real hole | File contents and stdout used to enter context unscreened (80k cap). |
| Locate can delete 5–6 tool rounds | Model still writes the answer; it skips exploration. |
| Decisions are code | Thresholds in `judge_decisions.py`. Pure functions. Tunable. |
| Observable | `JudgementMade`: tag, signals, enforced?, latency. |

* * *

## Cons

|  |  |
| --- | --- |
| Not ground truth | Parser/LSP beat a probability on syntax and types. |
| Cannot generate queries | Locate pattern = stopword-stripped identifiers. “How does auth work?” may miss `authenticate`. |
| Confidence compounds | 0.9⁴ ≈ 0.66. Resolver stopped before `list_symbols` → `find_symbol`. Fall through often, be right when you don’t. |
| Latency vs the brochure | Timeout 800ms. Screen fires on every large result. Fall-through pays classify **and** still runs `ask`. Advisory pays for nothing. |
| False positives already happened | `git status` scored as huge blast radius (it *observes* the repo). Prompt files need the ordinary-code brake. Thresholds are first guesses. |
| Orch / resolver clash | Orch has no FS tools. Seeding `search` into orch already stalled a turn. Inbox handoffs had to be excluded. |
| Knob sprawl | Global mode + ~10 site overrides. Write gate refuses to inherit `enforcing`. Correct, and not “turn the judge on.” |
| Extra vendor on the hot path | Key, cost, 800ms tail of no-ops. Cache (512) helps re-reads, not first reads. |
| Gaps on the read path | No `list_symbols` re-rank. Verify does not run on `search`/`read_file`. JEV will not stop `list_files` first — that’s still a prompt. |
| Screen is windowed | Injection after char 4000 is out of scope. |

* * *

## The split worth keeping

| Enumerable (JEV can pick) | Not enumerable (LLM must generate) |
| --- | --- |
| `read_file` given a known path | `search` query |
| `find_symbol` given a name from the outline | `str_replace` / patch body |
| `goto_definition` given `find_symbol` coords | `run_command` |

**Navigation can stop being an agent. Editing cannot.**

Ship each site `advisory` until the false-positive rate is a number. Let JEV reorder rg and flag hostile bytes. Do not let it invent the next path.
