pi-fovea 0.24.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -23
- package/dist/cli.mjs +291 -192
- package/docs/substrate.md +23 -0
- package/package.json +6 -2
- package/skills/pi-fovea/SKILL.md +5 -3
- package/src/core/build.ts +1 -1
- package/src/core/extract.ts +39 -1
- package/src/core/git.ts +52 -3
- package/src/core/graph.ts +92 -4
- package/src/core/heat.ts +11 -10
- package/src/core/ops.ts +58 -57
- package/src/core/render.ts +21 -14
- package/src/core/session.ts +1 -17
- package/src/core/state.ts +1 -7
- package/src/core/types.ts +23 -1
- package/src/index.ts +5 -31
- package/src/substrate.ts +46 -0
- package/src/core/review-read.ts +0 -66
- package/src/core/review.ts +0 -136
package/README.md
CHANGED
|
@@ -58,7 +58,7 @@ and test commands in your loop. CI has the final say.
|
|
|
58
58
|
| `fovea_sketch` | where is everything? | production-first silhouette plus explicit discovery/extraction coverage; test and fixture architecture stays collapsed |
|
|
59
59
|
| `fovea_focus` | what is this? | exact symbols/routes/protocol ids, evidenced relationships, path-gap reasons, suggested reads, scopes, and deterministic `fresh` views |
|
|
60
60
|
| `fovea_dwell` | what else? | widens the current focus, or expires safely when its graph generation changed |
|
|
61
|
-
| `fovea_impact` | what does this touch? | hunk-precise seeds, evidenced
|
|
61
|
+
| `fovea_impact` | what does this touch? | hunk-precise seeds, evidenced impact paths, co-change companions, and conserved diffusion heat |
|
|
62
62
|
| `grep` *(default hybrid)* | graph or text? | bare identifiers, qualified symbols, repo paths, and routes use Fovea; search options and obvious regex retain native grep |
|
|
63
63
|
|
|
64
64
|
Focus normalizes camelCase and common inflections. An approximate name such as
|
|
@@ -66,7 +66,7 @@ Focus normalizes camelCase and common inflections. An approximate name such as
|
|
|
66
66
|
match returns the nearest symbols plus their locations. Direct graph edges
|
|
67
67
|
carry labels such as caller, callee, route, shared literal, and co-change, plus
|
|
68
68
|
deterministic `strategy` / `rule` / `source` evidence. Every tool result includes
|
|
69
|
-
a coverage
|
|
69
|
+
a coverage report; an explicit missing path says whether it is unsupported,
|
|
70
70
|
ignored, oversized, generated, unreadable, Git-listed but unavailable, beyond
|
|
71
71
|
the file cap, behind a closed nested-repository boundary, or absent. Symbols
|
|
72
72
|
that merely share a file stay collapsed.
|
|
@@ -181,8 +181,11 @@ limits accept environment overrides:
|
|
|
181
181
|
| `FOVEA_SPAWN_CONCURRENCY` | `3` | concurrent ast-grep/git child processes (ast-grep parallelizes parsing inside each process; values above ~4 rarely help) |
|
|
182
182
|
| `FOVEA_MEMORY_HALF_LIFE_HOURS` | `48` | wall-clock half-life of the per-node sync memory (charged cascade warmth) |
|
|
183
183
|
| `FOVEA_IO_CONCURRENCY` | `32` | concurrent file stat/read operations |
|
|
184
|
+
| `FOVEA_GIT_UNTRACKED_CACHE` | enabled | set to `0` to disable the native Git untracked-directory cache requested by freshness probes |
|
|
184
185
|
| `FOVEA_MAX_SUBMODULE_DEPTH` | `4` | recursion cap for nested submodules |
|
|
185
186
|
|
|
187
|
+
Freshness probes still consult Git on every call; there is no new time-based shortcut. One porcelain-v2 status supplies both HEAD and changes, with a legacy fallback. At a verified worktree root, Fovea requests Git's native untracked-directory cache and omits the redundant dot pathspec that prevents its use. Subroots and Git environment overrides keep their explicit path scope. This can update Git index metadata, but does not change Git configuration files. Set `FOVEA_GIT_UNTRACKED_CACHE=0` to opt out; `GIT_OPTIONAL_LOCKS=0` can also prevent cache updates. Dirty files, new directories, ignore changes, and repository-boundary changes still go through freshness checks.
|
|
188
|
+
|
|
186
189
|
Files over the size cap keep their place in the model's view of the repo.
|
|
187
190
|
Failed extractions do the same. You find both in `/fovea status` and in tool
|
|
188
191
|
details.
|
|
@@ -303,29 +306,21 @@ environment override still turns sync off with:
|
|
|
303
306
|
FOVEA_TURN_SYNC=off pi
|
|
304
307
|
```
|
|
305
308
|
|
|
306
|
-
##
|
|
309
|
+
## Change impact as heat
|
|
307
310
|
|
|
308
|
-
`fovea_impact`
|
|
311
|
+
`fovea_impact` ranks relevant context under a strict token budget. It does not track inspection or certify feature completeness.
|
|
309
312
|
|
|
310
|
-
|
|
313
|
+
Seeds come from the diff. Hunk parsing maps each change to the symbols that contain it. One unit of mass goes to each changed file: `0.2` on the file node, `0.8` over the touched symbols in proportion to `sqrt(changed lines)`. Heat then spreads along static relationships, with historical co-change partners added as decaying seed heat. Edits that resist symbol-level location fall back to the file-node seed. New files, deletions, renames, untracked paths, and oversized diffs all take that path.
|
|
311
314
|
|
|
312
315
|
Historical co-change is a decaying **heat prior**, never a permanent graph edge. It counts up to 400 first-parent integration boundaries: merge net changes count once, not again through their constituent commits. Explicit `fixup!`/`squash!` followups join only uniquely resolved older subjects in that window. Time, author, shared issue numbers, and unlabeled "forgot this" do not group work. Boundaries are not proof of a semantic feature (release merges can mix work). Aggregates above 24 tracked files emit no pairs but retain directional touch counts; two distinct retained units are needed for a pair, three for expectations. Raw history caching includes shallow-state identity; recency still applies at use. Focus, sketch, and the structural diffusion operator remain unchanged.
|
|
313
316
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
A successful local `read` records only returned source windows at a content SHA-1. `seen` means source exposure, not whole-file inspection or understanding. The host checks matching text and stable before/after snapshots; requested limits are not treated as returned lines. Failed, diagnostic-only, rewritten, or racing reads earn no acknowledgment. Snapshot capture is bounded to 1 MiB per retained file, with at most 16 merged windows per revision (`windowsOmitted` reports loss). Reads before a file enters review memory are not tracked. Thus `unread` means **no matching read observed while retained**, not proof that nobody read it.
|
|
317
|
-
|
|
318
|
-
A changed content hash makes previous exposure `stale`, including comment-only, shell, Fabric, and editor changes when the graph next refreshes. Reverting a file does not erase the stale marker; another matching read does. This is file-local exposure history, not a sound dependency-based verification system. Semantic surprise and turn steering retain their existing separate rules.
|
|
317
|
+
Impact details describe the current cascade:
|
|
319
318
|
|
|
320
|
-
|
|
319
|
+
- `warmedMass`, `warmedReasons`, and `warmedEvidence`: per-file heat and the causal channels supporting the ranking.
|
|
320
|
+
- `expectedButUnchanged`: likely companions inferred from directional co-change history, not required edits.
|
|
321
|
+
- `conservedMass`: degree-corrected random-walk heat, reported separately from the raw scale used by sync.
|
|
321
322
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
- `expectedButUnchanged`: likely missing companions inferred from directional co-change history. These are review suggestions, not required edits.
|
|
325
|
-
- `conservedMass`: degree-corrected random-walk heat; mathematical conservation of diffusion mass is unrelated to review accounting. Sync keeps its raw scale.
|
|
326
|
-
- `review`: retained entries with salience, reasons, revision, exposure windows, `unseen`/`seen`/`stale` totals, epoch, and retention-loss information. This replaces the former `obligations` and top-level `epoch` fields; the verification transition has been removed rather than relabeled.
|
|
327
|
-
|
|
328
|
-
The budgeted trailer says `review memory · 3 unread · 1 stale · 2 seen (windows only)` and names the strongest pending suggestions. Evictions and prior-epoch loss appear there when budget permits and always in structured details. Cold pending entries remain accessible in the full impact overflow list. Zero unread or stale entries means no pending *retained review suggestions*, never feature completion. The CLI has no host read events; inspection tracking belongs to the in-session extension.
|
|
323
|
+
Repeated impact calls do not accumulate pending work. The result and its overflow list describe the current seeds, graph, and historical heat prior; a seedless query does not carry earlier suggestions forward. Focus and dwell retain only their own progressive-disclosure context, while graph refresh and turn sync keep navigation current after source changes.
|
|
329
324
|
|
|
330
325
|
`docs/heat-diffusion.md` has the full mechanics.
|
|
331
326
|
|
|
@@ -350,10 +345,7 @@ effective while its global default is being edited.
|
|
|
350
345
|
| `tools.grepMode` | `"augment"` | `"augment"\u0020keeps native grep and appends a Fovea graph section to symbol-query results (works with `pi.grep` inside fabric_exec too); `"replace"` keeps the legacy takeover where bare symbol queries navigate the graph instead of returning lines; `"off"` is native grep only. The legacy boolean `tools.replaceGrep` still parses (`true`\u2192`"replace"`, `false`\u2192`"off"`) and loses to an explicit `grepMode`. |
|
|
351
346
|
| `tools.grepAugmentBudget` | `512` | token cap for the appended graph section |
|
|
352
347
|
|
|
353
|
-
Budgets cap the rendered view, not the map
|
|
354
|
-
impact truncate results for budget, the full list spills to
|
|
355
|
-
`$TMPDIR/pi-fovea-<op>-<hash>.txt` and the footer names the path — read or grep
|
|
356
|
-
the file for the remainder. `fovea_dwell` remains the semantic widen.
|
|
348
|
+
Budgets cap the rendered view, not the map. Focus and dwell keep every eligible candidate recoverable beyond both the token budget and the 400-candidate display cap. Their `details.lit` counts the full eligible set, while `details.candidateOmitted` counts display-cap exclusions. Whenever a view truncates, the full list spills to `$TMPDIR/pi-fovea-<op>-<hash>.txt` if writable, and the footer names the path. Read or grep that artifact for the remainder; a failed write never produces a false path. Scope filters, already-disclosed nodes, and nodes below the heat cutoff are not added to overflow. `fovea_dwell` remains the semantic widen.
|
|
357
349
|
|
|
358
350
|
## How routes are found
|
|
359
351
|
|
|
@@ -472,6 +464,12 @@ filesystem walk reports an unknown omission count instead of inventing one.
|
|
|
472
464
|
`/fovea status` and `fovea status` use this same ledger rather than comparing
|
|
473
465
|
unlike tracked and supported file counts.
|
|
474
466
|
|
|
467
|
+
Import diagnostics live in `details.coverage.imports`: captured sites are classified as resolved, possible, or unresolved, with bounded examples, cap counts, and languages lacking import readers. Unresolved includes external packages and unmodeled resolution—not necessarily broken code. JS/TS literal `import()` and `require()` targets resolve normally. A relative one-hole expression such as `import('./plugins/' + name + '.js')` or ``require(`./plugins/${name}.js`)`` can connect up to 32 matching in-scope files through explicitly **possible** import edges. A family scans at most 4,096 files; exceeding either limit emits no partial family and reports the cap. Unknown expressions remain unresolved. Possible imports do not become exact call or test edges.
|
|
468
|
+
|
|
469
|
+
This is a finite candidate approximation, not a bound on runtime values: variables can contain traversal segments or name generated, external, or excluded modules. Conductance encodes a prior, not a calibrated probability. Selected files have file nodes by construction; relationship completeness, future edits, runtime behavior, and business requirements do not follow from that membership.
|
|
470
|
+
|
|
471
|
+
The [39-repository paired corpus](docs/coverage-corpus.md) checks this boundary without repository execution or useful co-change history. It distinguishes ordinary diffused probes from uniform-field display-cap stress, records unsupported/excluded files, and retains failures rather than replacing repositories. The dynamic-family observation is limited to one Vue build utility; regression fixtures separately exercise runtime plugin loading and capped/unknown cases.
|
|
472
|
+
|
|
475
473
|
## How it works
|
|
476
474
|
|
|
477
475
|
The repo compiles to a typed graph. Your question becomes a source vector $s$
|
|
@@ -522,6 +520,12 @@ special case of this field. [docs/heat-diffusion.md](docs/heat-diffusion.md)
|
|
|
522
520
|
walks through conductance tiers, specificity bridges, hub gravity, and inferred
|
|
523
521
|
regions.
|
|
524
522
|
|
|
523
|
+
## Snapshot substrate API
|
|
524
|
+
|
|
525
|
+
`pi-fovea/substrate` exposes a versioned, session-free graph and heat interface for
|
|
526
|
+
consumers such as pi-contour. It assembles caller-supplied immutable facts without
|
|
527
|
+
discovering files or reading a live worktree. See [docs/substrate.md](docs/substrate.md).
|
|
528
|
+
|
|
525
529
|
## Languages
|
|
526
530
|
|
|
527
531
|
Full symbol and call extraction: **TypeScript, TSX, JavaScript, Python, Go, and Rust**.
|
|
@@ -533,11 +537,15 @@ Exact contract topology: **Protocol Buffers (`.proto`) and GraphQL (`.graphql`,
|
|
|
533
537
|
|
|
534
538
|
```sh
|
|
535
539
|
bun install
|
|
536
|
-
bun run check # typecheck + full vitest suite
|
|
540
|
+
bun run check # typecheck + full vitest suite + knip
|
|
537
541
|
bun run bench # rate–distortion and refresh bench against ../pi-fabric
|
|
538
542
|
bun run bench tests/fixtures/mini # self-contained smoke run
|
|
539
543
|
```
|
|
540
544
|
|
|
545
|
+
The [warm-path performance report](docs/performance.md) compares the coverage-complete implementation with the optimized version. `bun run corpus:performance <coverage-work> <before-source> <after-source> [rounds]` runs alternating, isolated comparisons with a shared extraction snapshot, independent Git indexes, and exact graph, focus/dwell/sketch, and overflow-content checks. It does not trade fewer candidates or weaker freshness checks for speed. For Node, run `NODE_OPTIONS='--import tsx' node scripts/performance-corpus.mjs ...`; development dependencies are required.
|
|
546
|
+
|
|
547
|
+
Warm matching derives query terms once and caches normalized symbol names by weak node identity, checking renames before reuse. Focus builds only the heat orders currently needed; dwell appends missing orders without replacing its existing basis. No new kernel or review state is introduced. Independent cold extraction can select different literal-join locations when capture order varies, so this paired benchmark deliberately makes no cold-extraction speedup claim.
|
|
548
|
+
|
|
541
549
|
The developer benchmark gates timings on semantic equivalence: cold versus
|
|
542
550
|
cached builds, and forced refresh versus clean rebuild after unchanged,
|
|
543
551
|
location-only, semantic, added-file, and deleted-file scenarios in disposable
|