uncoded 2.0.0__tar.gz → 2.1.0__tar.gz
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.
- uncoded-2.1.0/.agents/skills/uncoded-code-navigation/SKILL.md +106 -0
- {uncoded-2.0.0/.claude → uncoded-2.1.0/.agents}/skills/uncoded-coherence-review/SKILL.md +123 -112
- uncoded-2.1.0/.agents/skills/uncoded-doc-navigation/SKILL.md +24 -0
- uncoded-2.1.0/.claude/skills/uncoded-code-navigation/SKILL.md +106 -0
- {uncoded-2.0.0/.agents → uncoded-2.1.0/.claude}/skills/uncoded-coherence-review/SKILL.md +123 -112
- uncoded-2.1.0/.claude/skills/uncoded-doc-navigation/SKILL.md +24 -0
- uncoded-2.1.0/.markdownlint-cli2.yaml +5 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.pre-commit-config.yaml +11 -0
- uncoded-2.1.0/.prettierrc +4 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/docs.yaml +2 -1
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/namespace.yaml +13 -2
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/src/uncoded/body.pyi +1 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/src/uncoded/cli.pyi +1 -1
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/src/uncoded/docs_map.pyi +2 -1
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/src/uncoded/extract.pyi +1 -1
- uncoded-2.1.0/.uncoded/stubs/src/uncoded/markers.pyi +3 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/src/uncoded/namespace_map.pyi +1 -0
- uncoded-2.1.0/.uncoded/stubs/src/uncoded/read_helpers.pyi +14 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/src/uncoded/refs.pyi +1 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/src/uncoded/resolver.pyi +1 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/src/uncoded/skill.pyi +1 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/tests/test_body.pyi +3 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/tests/test_cli.pyi +12 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/tests/test_extract.pyi +4 -1
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/tests/test_skill.pyi +4 -0
- uncoded-2.1.0/AGENTS.md +80 -0
- uncoded-2.1.0/PKG-INFO +379 -0
- uncoded-2.1.0/README.md +358 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/pyproject.toml +16 -6
- {uncoded-2.0.0 → uncoded-2.1.0}/src/uncoded/body.py +4 -4
- {uncoded-2.0.0 → uncoded-2.1.0}/src/uncoded/cli.py +68 -72
- uncoded-2.1.0/src/uncoded/code_navigation.md +99 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/src/uncoded/coherence_review.md +120 -111
- uncoded-2.1.0/src/uncoded/doc_navigation.md +17 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/src/uncoded/docs_map.py +6 -5
- {uncoded-2.0.0 → uncoded-2.1.0}/src/uncoded/extract.py +8 -8
- uncoded-2.1.0/src/uncoded/markers.py +3 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/src/uncoded/namespace_map.py +3 -2
- uncoded-2.1.0/src/uncoded/read_helpers.py +62 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/src/uncoded/refs.py +4 -3
- {uncoded-2.0.0 → uncoded-2.1.0}/src/uncoded/resolver.py +7 -6
- {uncoded-2.0.0 → uncoded-2.1.0}/src/uncoded/skill.py +16 -10
- {uncoded-2.0.0 → uncoded-2.1.0}/src/uncoded/sync.py +3 -3
- {uncoded-2.0.0 → uncoded-2.1.0}/tests/test_body.py +10 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/tests/test_cli.py +43 -3
- {uncoded-2.0.0 → uncoded-2.1.0}/tests/test_extract.py +17 -3
- {uncoded-2.0.0 → uncoded-2.1.0}/tests/test_skill.py +21 -4
- uncoded-2.0.0/.agents/skills/uncoded-code-navigation/SKILL.md +0 -109
- uncoded-2.0.0/.agents/skills/uncoded-doc-navigation/SKILL.md +0 -22
- uncoded-2.0.0/.claude/skills/uncoded-code-navigation/SKILL.md +0 -109
- uncoded-2.0.0/.claude/skills/uncoded-doc-navigation/SKILL.md +0 -22
- uncoded-2.0.0/.markdownlint-cli2.yaml +0 -5
- uncoded-2.0.0/.uncoded/stubs/src/uncoded/read_helpers.pyi +0 -7
- uncoded-2.0.0/AGENTS.md +0 -70
- uncoded-2.0.0/PKG-INFO +0 -367
- uncoded-2.0.0/README.md +0 -346
- uncoded-2.0.0/src/uncoded/code_navigation.md +0 -104
- uncoded-2.0.0/src/uncoded/doc_navigation.md +0 -17
- uncoded-2.0.0/src/uncoded/read_helpers.py +0 -25
- {uncoded-2.0.0 → uncoded-2.1.0}/.github/workflows/ci.yml +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.github/workflows/publish.yml +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.gitignore +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/src/uncoded/__init__.pyi +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/src/uncoded/ast_helpers.pyi +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/src/uncoded/config.pyi +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/src/uncoded/stubs.pyi +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/src/uncoded/sync.pyi +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/src/uncoded/yaml_tree.pyi +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/tests/test_config.pyi +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/tests/test_docs_map.pyi +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/tests/test_namespace_map.pyi +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/tests/test_refs.pyi +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/tests/test_stubs.pyi +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/tests/test_sync.pyi +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/.uncoded/stubs/tests/test_uncoded.pyi +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/CLAUDE.md +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/LICENSE +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/src/uncoded/__init__.py +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/src/uncoded/ast_helpers.py +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/src/uncoded/config.py +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/src/uncoded/stubs.py +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/src/uncoded/yaml_tree.py +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/tests/__init__.py +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/tests/test_config.py +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/tests/test_docs_map.py +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/tests/test_namespace_map.py +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/tests/test_refs.py +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/tests/test_stubs.py +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/tests/test_sync.py +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/tests/test_uncoded.py +0 -0
- {uncoded-2.0.0 → uncoded-2.1.0}/uv.lock +0 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: uncoded-code-navigation
|
|
3
|
+
description: Use before searching, reading, or editing Python source in a codebase indexed by uncoded. This covers locating a symbol, reading a definition, or checking references before you refactor, rename, or delete.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- Generated by uncoded — do not edit; regeneration overwrites. -->
|
|
7
|
+
|
|
8
|
+
# Code Navigation
|
|
9
|
+
|
|
10
|
+
This codebase uses [uncoded](https://github.com/alimanfoo/uncoded) to maintain a
|
|
11
|
+
symbol index over its source code, with two associated CLI tools: `uncoded body`
|
|
12
|
+
for reading a symbol's body and `uncoded refs` for finding references.
|
|
13
|
+
|
|
14
|
+
## The dispatch rule
|
|
15
|
+
|
|
16
|
+
**If your search term is the name of a Python symbol, use the index. Python
|
|
17
|
+
symbols are classes, functions, methods, attributes, and module-level constants.
|
|
18
|
+
If it's a pattern, regex, or free-text phrase, use grep.**
|
|
19
|
+
|
|
20
|
+
This applies to every tool call where you find code, not just the first in the
|
|
21
|
+
session. The pretrained reflex for "find X" is grep, and that reflex is wrong
|
|
22
|
+
here. Reaching for `grep -rn 'def parse_config'` to read a function's body is a
|
|
23
|
+
case for `uncoded body`. Reaching for `grep -rn 'validate_input'` to check
|
|
24
|
+
callers before a refactor is a case for `uncoded refs`. Reaching for `grep` then
|
|
25
|
+
`Edit` to delete dead code is a case for `uncoded refs` to confirm the code is
|
|
26
|
+
dead, then `Edit`. The grep version of any of these is noisier and less
|
|
27
|
+
reliable. Grep matches comments, strings, and unrelated attributes. Grep misses
|
|
28
|
+
re-exports, so caller and delete checks come back incomplete. Grep forces offset
|
|
29
|
+
arithmetic to slice a body. The indexed tools don't.
|
|
30
|
+
|
|
31
|
+
## How to execute the rule
|
|
32
|
+
|
|
33
|
+
The index has two parts (a namespace map and per-file stubs) and three steps
|
|
34
|
+
(orient, understand, act).
|
|
35
|
+
|
|
36
|
+
**Step 1: Orient. Read the namespace map first.** Before answering the user,
|
|
37
|
+
before any other tool call:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
Read .uncoded/namespace.yaml
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
This lists every symbol in the codebase: directories, files, classes, methods,
|
|
44
|
+
functions. Without it loaded, "find X" answers come from pretrained guesses.
|
|
45
|
+
They reflect what a project like this probably contains, not what is actually
|
|
46
|
+
here. Read it once, in full, at session start.
|
|
47
|
+
|
|
48
|
+
**Step 2: Understand. Read the `.pyi` stub before any `.py` source.** Stub paths
|
|
49
|
+
mirror source paths under `.uncoded/stubs/`:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
src/foo/bar.py → .uncoded/stubs/src/foo/bar.pyi
|
|
53
|
+
tests/test_foo.py → .uncoded/stubs/tests/test_foo.pyi
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Read the stub for every file you intend to touch or reference, including tests.
|
|
57
|
+
The stub contains imports, every signature with types, module-level assignments,
|
|
58
|
+
and class attributes. That is enough for most navigation. Skipping straight to
|
|
59
|
+
source means reading many lines to learn what the stub would have told you in
|
|
60
|
+
one. If no stub exists at the expected path, the file has no symbols indexed. In
|
|
61
|
+
that narrow case, read source directly.
|
|
62
|
+
|
|
63
|
+
**Step 3: Act.** Use `uncoded body` to read a symbol's body. Use `uncoded refs`
|
|
64
|
+
to find every reference to a symbol. Use `Edit` (with `uncoded body`'s output as
|
|
65
|
+
`old_string`) to change a symbol. With the map and stub loaded, you have the
|
|
66
|
+
exact `relative_path` and `name_path` each tool needs. Use `ClassName/method`
|
|
67
|
+
for a method and `function_name` for a top-level function. Per task:
|
|
68
|
+
|
|
69
|
+
- **Read a symbol's body.** `uvx uncoded body <name_path> --in <relative_path>`
|
|
70
|
+
prints the symbol's source text to stdout, byte-identical to disk. Returns
|
|
71
|
+
exactly the symbol. No offset arithmetic, no risk of reading too much. Its
|
|
72
|
+
output has every byte `Edit` needs as `old_string`. You need no extra `Read`
|
|
73
|
+
for partial edits. Stay on stubs for a wider sweep.
|
|
74
|
+
|
|
75
|
+
- **Find every reference to a symbol.**
|
|
76
|
+
`uvx uncoded refs <name_path> --in <relative_path>`. Prints one reference per
|
|
77
|
+
line as `file:line:col`, sorted. Grep on the name misses re-exports and adds
|
|
78
|
+
false positives from comments, strings, and attribute lookups on other types.
|
|
79
|
+
If the next move depends on the answer being complete, grep cannot give you
|
|
80
|
+
that.
|
|
81
|
+
|
|
82
|
+
- **Edit a symbol.** `uvx uncoded body <name_path> --in <relative_path>` gives
|
|
83
|
+
the exact `old_string`; then `Edit` to apply the change.
|
|
84
|
+
|
|
85
|
+
- **Rename.** `uvx uncoded refs <name_path> --in <relative_path>` enumerates
|
|
86
|
+
every site; then `Edit` at each.
|
|
87
|
+
|
|
88
|
+
- **Safely delete.** `uvx uncoded refs <name_path> --in <relative_path>` must
|
|
89
|
+
return empty; then `Edit` to remove.
|
|
90
|
+
|
|
91
|
+
## Where Read, Edit, and grep are still the right tools
|
|
92
|
+
|
|
93
|
+
The rule is about source navigation by symbol name. Outside that, Read, Edit,
|
|
94
|
+
and grep stay correct:
|
|
95
|
+
|
|
96
|
+
- Free-text or pattern search outside source: Markdown, YAML, TOML, configs,
|
|
97
|
+
commit messages, notebook JSON, fixture data.
|
|
98
|
+
- Pattern search across signatures (regex over type annotations, decorator
|
|
99
|
+
usage, alias declarations). These are not symbol-name lookups, even though
|
|
100
|
+
they sit inside source.
|
|
101
|
+
- Partial-line edits inside a symbol body, once you have retrieved it via
|
|
102
|
+
`uncoded body`.
|
|
103
|
+
- The rare stub-less Python file that needs exploratory reading.
|
|
104
|
+
|
|
105
|
+
The dispatch rule turns on the search term. A symbol name goes to the index. A
|
|
106
|
+
regex or free-text phrase goes to grep.
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: uncoded-coherence-review
|
|
3
|
-
description:
|
|
3
|
+
description: Review a Python codebase for coherence. It sweeps for semantic drift, naming inconsistency, mismatch between a symbol's name, signature, and docstring, and structural incoherence. It produces a Markdown report of findings, with verbatim evidence and confidence levels, for human investigation. It assumes uncoded is installed (.uncoded/namespace.yaml and .uncoded/stubs/ present).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
<!-- Generated by uncoded — do not edit; regeneration overwrites. -->
|
|
7
|
+
|
|
6
8
|
# Coherence Review
|
|
7
9
|
|
|
8
10
|
A diagnostic sweep of a Python codebase for specific, observable symptoms of
|
|
@@ -13,67 +15,77 @@ human to investigate. Not a bug hunt, not a lint pass, not a refactor.
|
|
|
13
15
|
## Why coherence, and what you are looking for
|
|
14
16
|
|
|
15
17
|
A codebase accumulates corruption differently from how it accumulates bugs. Bugs
|
|
16
|
-
announce themselves
|
|
17
|
-
passes every integrity check. It is
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
announce themselves. Tests fail, users complain, exceptions raise. Corruption
|
|
19
|
+
passes every integrity check. It is a slow divergence between things that should
|
|
20
|
+
match:
|
|
21
|
+
|
|
22
|
+
- what the code claims to mean and what it actually does
|
|
23
|
+
- how one part of the codebase names a concept and how another names the same
|
|
24
|
+
concept
|
|
25
|
+
- an architecture as declared and an architecture as practised
|
|
26
|
+
|
|
27
|
+
Each local decision that contributed to it was reasonable. The accumulation is
|
|
28
|
+
not.
|
|
22
29
|
|
|
23
30
|
Corruption's one observable signature is **internal inconsistency**. Not
|
|
24
|
-
absolute wrongness
|
|
31
|
+
absolute wrongness. That requires a reference outside the code, which is not
|
|
25
32
|
available here. Just pairwise disagreement between things that ought to agree:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
|
|
34
|
+
- a name and its behaviour
|
|
35
|
+
- two names for the same concept
|
|
36
|
+
- a docstring and the signature it sits on
|
|
37
|
+
- a declared architecture and the actual import graph
|
|
38
|
+
|
|
39
|
+
Every symptom in the sweeps below is a form of inconsistency. The review's job
|
|
40
|
+
is to find these disagreements. It does not diagnose root cause and does not fix
|
|
41
|
+
them.
|
|
30
42
|
|
|
31
43
|
## What this skill is not
|
|
32
44
|
|
|
33
45
|
- **Not a bug-finder.** Bugs are the job of testing and code review. A coherence
|
|
34
46
|
review can run on code that passes every test and still find plenty.
|
|
35
|
-
- **Not a style pass.** Tabs versus spaces, docstring format, import ordering
|
|
47
|
+
- **Not a style pass.** Tabs versus spaces, docstring format, import ordering:
|
|
36
48
|
irrelevant. Linters exist.
|
|
37
49
|
- **Not a refactor.** No proposing fixes, no suggesting renames, no rewriting
|
|
38
50
|
code. The output is findings. The human decides what to do with them.
|
|
39
|
-
- **Not a general code review.** Performance, security, correctness
|
|
51
|
+
- **Not a general code review.** Performance, security, correctness: out of
|
|
40
52
|
scope unless they happen to manifest as a coherence symptom.
|
|
41
53
|
|
|
42
54
|
## Prerequisites
|
|
43
55
|
|
|
44
|
-
Verify by reading `.uncoded/namespace.yaml
|
|
45
|
-
proceed. If not, stop and tell the user to run `uvx uncoded sync` first
|
|
46
|
-
depends on the index.
|
|
56
|
+
Verify by reading `.uncoded/namespace.yaml`. If it exists and is non-empty,
|
|
57
|
+
proceed. If not, stop and tell the user to run `uvx uncoded sync` first. The
|
|
58
|
+
review depends on the index.
|
|
47
59
|
|
|
48
|
-
The structural sweep uses `uncoded refs` for cross-file reference checks
|
|
49
|
-
|
|
60
|
+
The structural sweep uses `uncoded refs` for cross-file reference checks. It
|
|
61
|
+
ships with uncoded itself and is always available when the index is present.
|
|
50
62
|
|
|
51
63
|
## Workflow
|
|
52
64
|
|
|
53
65
|
The review proceeds in four sweeps, each building on the previous:
|
|
54
66
|
|
|
55
|
-
1. **Orient
|
|
56
|
-
2. **Lexical sweep
|
|
57
|
-
3. **Promissory sweep
|
|
58
|
-
|
|
59
|
-
via `uncoded body`.
|
|
60
|
-
4. **Structural sweep
|
|
67
|
+
1. **Orient**: load the navigation index and form a mental map.
|
|
68
|
+
2. **Lexical sweep**: read the namespace, look for naming-level inconsistency.
|
|
69
|
+
3. **Promissory sweep**: check each symbol's name / signature / docstring for
|
|
70
|
+
internal disagreement. Names and signatures come from the stub. Docstrings
|
|
71
|
+
come via `uncoded body`.
|
|
72
|
+
4. **Structural sweep**: combine namespace and imports to find boundary and
|
|
61
73
|
shape symptoms.
|
|
62
74
|
|
|
63
|
-
Do the sweeps in order. Write findings as you go
|
|
75
|
+
Do the sweeps in order. Write findings as you go. Do not hold them in memory
|
|
64
76
|
until the end.
|
|
65
77
|
|
|
66
78
|
## Step 1: Orient
|
|
67
79
|
|
|
68
|
-
Read `.uncoded/namespace.yaml` in full. This is the map
|
|
69
|
-
classes, methods, functions. Do not skim. Every public symbol in the codebase
|
|
70
|
-
|
|
80
|
+
Read `.uncoded/namespace.yaml` in full. This is the map: directories, files,
|
|
81
|
+
classes, methods, functions. Do not skim. Every public symbol in the codebase is
|
|
82
|
+
listed here, and the shape of the namespace itself is evidence.
|
|
71
83
|
|
|
72
84
|
While reading, note:
|
|
73
85
|
|
|
74
86
|
- The vocabulary the codebase uses for its core concepts
|
|
75
87
|
- The organisational logic (domain-driven? layered? feature-based? ad hoc?)
|
|
76
|
-
- Anything that surprises you
|
|
88
|
+
- Anything that surprises you: odd names, asymmetric organisation, suspicious
|
|
77
89
|
clusters
|
|
78
90
|
|
|
79
91
|
Also read `CLAUDE.md` if present, and follow any repo-specific navigation
|
|
@@ -91,18 +103,18 @@ symptom.
|
|
|
91
103
|
different names in different parts of the codebase. Examples: `fetch_user`,
|
|
92
104
|
`get_user`, `load_user`, `retrieve_user` all appearing as separate functions
|
|
93
105
|
doing substantively the same thing. `compute_*`, `calculate_*`, `derive_*` used
|
|
94
|
-
interchangeably. Two classes called `UserRecord` and `AccountProfile` that
|
|
95
|
-
|
|
106
|
+
interchangeably. Two classes called `UserRecord` and `AccountProfile` that model
|
|
107
|
+
the same entity.
|
|
96
108
|
|
|
97
109
|
Detection: scan the namespace for symbol clusters with verb or noun overlap.
|
|
98
|
-
Where suspicion arises, check the stub signatures and the source docstrings
|
|
99
|
-
|
|
110
|
+
Where suspicion arises, check the stub signatures and the source docstrings (via
|
|
111
|
+
`uncoded body`) to confirm the candidates overlap in meaning.
|
|
100
112
|
|
|
101
|
-
**Qualifier accretion.** Names carrying modifiers that are fossils of
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
113
|
+
**Qualifier accretion.** Names carrying modifiers that are fossils of iteration:
|
|
114
|
+
`_new`, `_v2`, `_updated`, `_legacy`, `_real`, `_proper`, `_final`, `_fixed`.
|
|
115
|
+
Also prefix forms: `new_`, `old_`, `real_`. These are almost always worth
|
|
116
|
+
flagging. Someone needed to distinguish a new thing from an old thing, and the
|
|
117
|
+
distinction was never resolved.
|
|
106
118
|
|
|
107
119
|
Detection: scan the namespace for these qualifier patterns.
|
|
108
120
|
|
|
@@ -114,11 +126,11 @@ without looking outward.
|
|
|
114
126
|
Detection: look for directories whose namespace entries share few word-roots
|
|
115
127
|
with the rest of the codebase.
|
|
116
128
|
|
|
117
|
-
**Collision with drift.** The same name appearing in multiple places with
|
|
118
|
-
|
|
129
|
+
**Collision with drift.** The same name appearing in multiple places with subtly
|
|
130
|
+
different meanings, visible as different signatures, different docstring
|
|
119
131
|
content, or different domain associations.
|
|
120
132
|
|
|
121
|
-
Detection: identify name collisions in the namespace
|
|
133
|
+
Detection: identify name collisions in the namespace. Then compare signatures
|
|
122
134
|
(from the stubs) and docstrings (via `uncoded body`) to see whether the uses
|
|
123
135
|
agree.
|
|
124
136
|
|
|
@@ -126,11 +138,10 @@ agree.
|
|
|
126
138
|
|
|
127
139
|
Examine each public symbol's name / signature / docstring triple for internal
|
|
128
140
|
disagreement. Load each source file's stub once for the names and signatures
|
|
129
|
-
across that file's symbols. Then, for each non-trivial public symbol
|
|
130
|
-
trivial one-liners and `__init__` with no meaningful body), run
|
|
141
|
+
across that file's symbols. Then, for each non-trivial public symbol, run
|
|
131
142
|
`uvx uncoded body <name_path> --in <relative_path>` to read the symbol's source.
|
|
132
|
-
|
|
133
|
-
finding that needs it.
|
|
143
|
+
Skip trivial one-liners and `__init__` with no meaningful body. The docstring is
|
|
144
|
+
at the top. The rest of the body is available for any finding that needs it.
|
|
134
145
|
|
|
135
146
|
**Name–signature mismatch.** Does the name's verb fit the signature's return? A
|
|
136
147
|
function called `validate_*` that returns the validated object rather than
|
|
@@ -147,79 +158,80 @@ more specific, more general, or simply different from what the name advertises?
|
|
|
147
158
|
"Normalises and validates the record" on a function called `check_record`.
|
|
148
159
|
|
|
149
160
|
**Defensive docstrings.** Docstrings that warn about the function rather than
|
|
150
|
-
describe it. "Note: this does not actually X despite the name." "Do not use
|
|
151
|
-
|
|
161
|
+
describe it. "Note: this does not actually X despite the name." "Do not use this
|
|
162
|
+
for Y; use Z instead." These are confessions. Someone noticed drift and
|
|
152
163
|
documented it rather than fixing it.
|
|
153
164
|
|
|
154
|
-
Quote evidence verbatim. The stub excerpt is the evidence for name and
|
|
155
|
-
|
|
156
|
-
|
|
165
|
+
Quote evidence verbatim. The stub excerpt is the evidence for name and signature
|
|
166
|
+
findings. The docstring read via `uncoded body` is the evidence for any
|
|
167
|
+
docstring-related finding.
|
|
157
168
|
|
|
158
|
-
**When confidence needs the body.** Consult the implementation in the body
|
|
159
|
-
|
|
160
|
-
name
|
|
161
|
-
docstring you want to verify against the body.
|
|
162
|
-
offset arithmetic
|
|
163
|
-
during this sweep.
|
|
169
|
+
**When confidence needs the body.** Consult the implementation in the body when
|
|
170
|
+
a finding's confidence needs it. Two cases call for this. The first is a
|
|
171
|
+
name-behaviour mismatch the docstring alone does not settle. The second is a
|
|
172
|
+
defensive docstring you want to verify against the body. It targets the symbol
|
|
173
|
+
directly, with no offset arithmetic and no risk of over-reading. Never read a
|
|
174
|
+
whole source file during this sweep.
|
|
164
175
|
|
|
165
176
|
## Step 4: Structural sweep
|
|
166
177
|
|
|
167
|
-
Combine the namespace with the import graph and `uncoded refs` for
|
|
168
|
-
|
|
178
|
+
Combine the namespace with the import graph and `uncoded refs` for cross-file
|
|
179
|
+
reference resolution.
|
|
169
180
|
|
|
170
181
|
**Overgrown public surfaces / god modules.** A module or class whose public
|
|
171
182
|
namespace is much larger than its siblings, or spans obviously different
|
|
172
|
-
concerns. Look for outlier symbol counts
|
|
173
|
-
its neighbours have five
|
|
183
|
+
concerns. Look for outlier symbol counts. For example, a file with forty public
|
|
184
|
+
symbols where its neighbours have five, or a class with thirty methods covering
|
|
185
|
+
multiple domains.
|
|
174
186
|
|
|
175
187
|
**Boundary violations.** One module importing private symbols (leading
|
|
176
188
|
underscore) from another. Scan `from module import _thing` patterns across
|
|
177
189
|
stubs' import sections. Each instance is a finding.
|
|
178
190
|
|
|
179
191
|
**Cross-vocabulary imports.** Imports that cross domain boundaries in suspicious
|
|
180
|
-
directions
|
|
181
|
-
domain
|
|
182
|
-
meant to be independent. Flag candidates and note the
|
|
183
|
-
decide.
|
|
192
|
+
directions. For example, a `core/` or `utils/` module importing from a specific
|
|
193
|
+
business domain. Another is a module in domain A importing from domain B when
|
|
194
|
+
those domains appear meant to be independent. Flag candidates and note the
|
|
195
|
+
direction. Let the human decide.
|
|
184
196
|
|
|
185
|
-
**Zero-reference public symbols.** A public symbol (no leading underscore) with
|
|
186
|
-
references anywhere in the codebase. Either dead code or an unused API
|
|
197
|
+
**Zero-reference public symbols.** A public symbol (no leading underscore) with
|
|
198
|
+
no references anywhere in the codebase. Either dead code or an unused API
|
|
199
|
+
surface.
|
|
187
200
|
|
|
188
201
|
Check systematically, not by spot-check:
|
|
189
202
|
|
|
190
203
|
1. From the namespace map, list all public symbols in each source module.
|
|
191
|
-
2. Cross-reference with stub import sections
|
|
192
|
-
source module is live
|
|
204
|
+
2. Cross-reference with stub import sections. Any symbol imported by another
|
|
205
|
+
source module is live. Remove it from the candidate list. This culls the
|
|
193
206
|
obvious cases cheaply.
|
|
194
|
-
3. For remaining candidates, use
|
|
195
|
-
to verify. Empty output
|
|
207
|
+
3. For remaining candidates, use
|
|
208
|
+
`uvx uncoded refs <name_path> --in <relative_path>` to verify. Empty output
|
|
209
|
+
confirms no references.
|
|
196
210
|
4. Distinguish two sub-cases when reporting:
|
|
197
|
-
-
|
|
198
|
-
-
|
|
211
|
+
- _No references anywhere._ Dead code. Highest priority.
|
|
212
|
+
- _References only in tests._ The symbol is tested but not used in source. It
|
|
199
213
|
may be an exposed internal that should be private.
|
|
200
214
|
|
|
201
215
|
**Redundant public surface.** A public constant and a public parameterless
|
|
202
|
-
function in the same module where the function's sole body is
|
|
203
|
-
<constant>`. Both symbols being public exposes an implementation detail
|
|
204
|
-
unnecessarily
|
|
205
|
-
public parameterless functions near public constants
|
|
206
|
-
|
|
216
|
+
function in the same module where the function's sole body is
|
|
217
|
+
`return <constant>`. Both symbols being public exposes an implementation detail
|
|
218
|
+
unnecessarily. Only one needs to be public. Detection: use the stubs to find
|
|
219
|
+
public parameterless functions near public constants. Verify each candidate body
|
|
220
|
+
with `uvx uncoded body` before reporting.
|
|
207
221
|
|
|
208
222
|
## Report format
|
|
209
223
|
|
|
210
224
|
Save the report as `.uncoded/reviews/YYYY-MM-DD-HHMMSS.md`, using today's date
|
|
211
|
-
and current time
|
|
212
|
-
|
|
225
|
+
and current time. The timestamp preserves multiple runs on the same day. Create
|
|
226
|
+
the directory if it does not exist.
|
|
213
227
|
|
|
214
228
|
Use this structure:
|
|
215
229
|
|
|
216
230
|
```markdown
|
|
217
231
|
# Coherence Review — <repo name>
|
|
218
232
|
|
|
219
|
-
**Date:** YYYY-MM-DD
|
|
220
|
-
**
|
|
221
|
-
**Sweeps run:** lexical, promissory, structural
|
|
222
|
-
**Findings:** N total (N lexical · N promissory · N structural)
|
|
233
|
+
**Date:** YYYY-MM-DD **Symbols indexed:** N **Sweeps run:** lexical, promissory,
|
|
234
|
+
structural **Findings:** N total (N lexical · N promissory · N structural)
|
|
223
235
|
|
|
224
236
|
## Priority regions
|
|
225
237
|
|
|
@@ -228,22 +240,21 @@ Regions with two or more findings — examine these first:
|
|
|
228
240
|
- `path/to/file.py` — N findings
|
|
229
241
|
- ...
|
|
230
242
|
|
|
231
|
-
|
|
243
|
+
_(Omit this section if no region has more than one finding.)_
|
|
232
244
|
|
|
233
245
|
## Findings
|
|
234
246
|
|
|
235
247
|
### 1 · <symptom summary>
|
|
236
248
|
|
|
237
|
-
**Category:** lexical | promissory | structural
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
**Location:** `path/to/file.py` · `ClassName/method_name`
|
|
244
|
-
**Confidence:** high | medium | low
|
|
249
|
+
**Category:** lexical | promissory | structural **Symptom:** concept-duplication
|
|
250
|
+
| qualifier-accretion | vocabulary-island | collision-with-drift |
|
|
251
|
+
name-signature-mismatch | docstring-signature-mismatch | docstring-name-mismatch
|
|
252
|
+
| defensive-docstring | god-module | boundary-violation |
|
|
253
|
+
cross-vocabulary-import | zero-reference **Location:** `path/to/file.py` ·
|
|
254
|
+
`ClassName/method_name` **Confidence:** high | medium | low
|
|
245
255
|
|
|
246
256
|
**Evidence:**
|
|
257
|
+
|
|
247
258
|
> Verbatim quote from namespace.yaml, stub, source docstring (via
|
|
248
259
|
> `uncoded body`), or import statement.
|
|
249
260
|
|
|
@@ -258,30 +269,30 @@ One or two sentences describing the inconsistency. Not a diagnosis. Not a fix.
|
|
|
258
269
|
|
|
259
270
|
**Coverage, not filtering.** Report every finding at its confidence level. Do
|
|
260
271
|
not silently drop findings judged low-severity. A low-confidence finding with
|
|
261
|
-
clear evidence is useful
|
|
272
|
+
clear evidence is useful. The human can filter. A dropped finding is not.
|
|
262
273
|
|
|
263
274
|
**Confidence is part of the finding, not a gate.**
|
|
264
275
|
|
|
265
|
-
- `high
|
|
266
|
-
|
|
267
|
-
- `medium
|
|
268
|
-
- `low
|
|
276
|
+
- `high`: the inconsistency is explicit. Evidence is directly in the namespace,
|
|
277
|
+
the stub, or the source docstring
|
|
278
|
+
- `medium`: strongly implied but depends on judgement about intent
|
|
279
|
+
- `low`: pattern-based suspicion that needs human interpretation
|
|
269
280
|
|
|
270
281
|
**Evidence must be verbatim.** Quote the relevant namespace line, stub excerpt,
|
|
271
282
|
source docstring, or import statement exactly. A finding the human cannot
|
|
272
283
|
quickly verify is worse than no finding.
|
|
273
284
|
|
|
274
285
|
**One finding per inconsistency.** If a single symbol has a name–signature
|
|
275
|
-
mismatch and a docstring–name mismatch, that is two findings on the same
|
|
276
|
-
|
|
286
|
+
mismatch and a docstring–name mismatch, that is two findings on the same symbol,
|
|
287
|
+
not one combined finding. Let the report show the density.
|
|
277
288
|
|
|
278
289
|
**Do not propose fixes.** No renaming suggestions, no refactoring proposals, no
|
|
279
|
-
"this should be moved to". The finding describes what is inconsistent. The
|
|
280
|
-
|
|
290
|
+
"this should be moved to". The finding describes what is inconsistent. The human
|
|
291
|
+
owns remediation.
|
|
281
292
|
|
|
282
293
|
**Do not flag style.** Docstring format, type annotation style, import ordering,
|
|
283
|
-
naming conventions
|
|
284
|
-
|
|
294
|
+
and naming conventions are out of scope. Coherence is about semantic
|
|
295
|
+
consistency.
|
|
285
296
|
|
|
286
297
|
**Do not fabricate.** Every finding must be anchored to code you actually
|
|
287
298
|
examined. If a sweep suggests a pattern but you cannot find concrete instances,
|
|
@@ -292,9 +303,9 @@ do not include it.
|
|
|
292
303
|
If the codebase has more than ~1000 public symbols:
|
|
293
304
|
|
|
294
305
|
1. Complete the lexical sweep in full (the namespace is compact enough).
|
|
295
|
-
2. For the promissory sweep, prioritise
|
|
296
|
-
|
|
297
|
-
a representative sample of the rest
|
|
306
|
+
2. For the promissory sweep, prioritise core domain modules (identified from the
|
|
307
|
+
namespace structure) and any module that appeared in a lexical finding. Also
|
|
308
|
+
cover a representative sample of the rest, around 30% of remaining stubs.
|
|
298
309
|
3. For the structural sweep, focus on the module and package level first,
|
|
299
310
|
descending to individual symbols only where the higher-level scan raised
|
|
300
311
|
flags.
|
|
@@ -314,7 +325,7 @@ quoted verbatim.</flag>
|
|
|
314
325
|
|
|
315
326
|
<example>
|
|
316
327
|
<scenario>A function `validate_user(user)` whose signature returns `User` rather
|
|
317
|
-
than `bool` or `None
|
|
328
|
+
than `bool` or `None`. Its docstring says "Validates and returns the user
|
|
318
329
|
if valid, raising UserValidationError otherwise."</scenario>
|
|
319
330
|
<flag>Yes. Name–signature mismatch, medium confidence. The name reads as a
|
|
320
331
|
predicate but the behaviour is a validator-filter. Stub quoted as
|
|
@@ -326,7 +337,7 @@ evidence.</flag>
|
|
|
326
337
|
defining functions that wrap callables with LRU caching, with slightly different
|
|
327
338
|
cache-size defaults.</scenario>
|
|
328
339
|
<flag>Yes. Concept duplication, medium confidence. Both stubs quoted. Note the
|
|
329
|
-
difference
|
|
340
|
+
difference. The human may determine it is intentional.</flag>
|
|
330
341
|
</example>
|
|
331
342
|
|
|
332
343
|
<example>
|
|
@@ -347,7 +358,7 @@ not indicate drift.</flag>
|
|
|
347
358
|
<example>
|
|
348
359
|
<scenario>A function is 80 lines of non-trivial logic.</scenario>
|
|
349
360
|
<flag>No, not by itself. Complexity is not incoherence. Flag only if the
|
|
350
|
-
complexity manifests as inconsistency
|
|
361
|
+
complexity manifests as inconsistency. For example, the function's behaviour has
|
|
351
362
|
drifted from what its name or docstring promise.</flag>
|
|
352
363
|
</example>
|
|
353
364
|
|
|
@@ -355,6 +366,6 @@ drifted from what its name or docstring promise.</flag>
|
|
|
355
366
|
<scenario>The codebase uses both `Optional[X]` and `X | None` in different
|
|
356
367
|
files.</scenario>
|
|
357
368
|
<flag>No. Both are valid Python and mean the same thing. Flag only if the
|
|
358
|
-
semantics of absence differ
|
|
359
|
-
others raise, for the same kind of operation.</flag>
|
|
369
|
+
semantics of absence differ. For example, some functions return None on failure
|
|
370
|
+
while others raise, for the same kind of operation.</flag>
|
|
360
371
|
</example>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: uncoded-doc-navigation
|
|
3
|
+
description: Use before searching or reading a codebase's Markdown documentation indexed by uncoded. This covers locating which file and section cover a topic, or orienting to what documentation exists.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- Generated by uncoded — do not edit; regeneration overwrites. -->
|
|
7
|
+
|
|
8
|
+
# Documentation Navigation
|
|
9
|
+
|
|
10
|
+
This codebase uses [uncoded](https://github.com/alimanfoo/uncoded) to maintain a
|
|
11
|
+
documentation index.
|
|
12
|
+
|
|
13
|
+
**Step 1: Orient. Read the docs map first.** Before answering the user, before
|
|
14
|
+
any other tool call:
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
Read .uncoded/docs.yaml
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`.uncoded/docs.yaml` is an orientation outline: it lists every Markdown file and
|
|
21
|
+
its heading hierarchy. Read it in full, now.
|
|
22
|
+
|
|
23
|
+
**Step 2: Navigate.** Headings in the map are literal text. Use `Read` or `grep`
|
|
24
|
+
to navigate to a specific section identified in the map.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: uncoded-code-navigation
|
|
3
|
+
description: Use before searching, reading, or editing Python source in a codebase indexed by uncoded. This covers locating a symbol, reading a definition, or checking references before you refactor, rename, or delete.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- Generated by uncoded — do not edit; regeneration overwrites. -->
|
|
7
|
+
|
|
8
|
+
# Code Navigation
|
|
9
|
+
|
|
10
|
+
This codebase uses [uncoded](https://github.com/alimanfoo/uncoded) to maintain a
|
|
11
|
+
symbol index over its source code, with two associated CLI tools: `uncoded body`
|
|
12
|
+
for reading a symbol's body and `uncoded refs` for finding references.
|
|
13
|
+
|
|
14
|
+
## The dispatch rule
|
|
15
|
+
|
|
16
|
+
**If your search term is the name of a Python symbol, use the index. Python
|
|
17
|
+
symbols are classes, functions, methods, attributes, and module-level constants.
|
|
18
|
+
If it's a pattern, regex, or free-text phrase, use grep.**
|
|
19
|
+
|
|
20
|
+
This applies to every tool call where you find code, not just the first in the
|
|
21
|
+
session. The pretrained reflex for "find X" is grep, and that reflex is wrong
|
|
22
|
+
here. Reaching for `grep -rn 'def parse_config'` to read a function's body is a
|
|
23
|
+
case for `uncoded body`. Reaching for `grep -rn 'validate_input'` to check
|
|
24
|
+
callers before a refactor is a case for `uncoded refs`. Reaching for `grep` then
|
|
25
|
+
`Edit` to delete dead code is a case for `uncoded refs` to confirm the code is
|
|
26
|
+
dead, then `Edit`. The grep version of any of these is noisier and less
|
|
27
|
+
reliable. Grep matches comments, strings, and unrelated attributes. Grep misses
|
|
28
|
+
re-exports, so caller and delete checks come back incomplete. Grep forces offset
|
|
29
|
+
arithmetic to slice a body. The indexed tools don't.
|
|
30
|
+
|
|
31
|
+
## How to execute the rule
|
|
32
|
+
|
|
33
|
+
The index has two parts (a namespace map and per-file stubs) and three steps
|
|
34
|
+
(orient, understand, act).
|
|
35
|
+
|
|
36
|
+
**Step 1: Orient. Read the namespace map first.** Before answering the user,
|
|
37
|
+
before any other tool call:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
Read .uncoded/namespace.yaml
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
This lists every symbol in the codebase: directories, files, classes, methods,
|
|
44
|
+
functions. Without it loaded, "find X" answers come from pretrained guesses.
|
|
45
|
+
They reflect what a project like this probably contains, not what is actually
|
|
46
|
+
here. Read it once, in full, at session start.
|
|
47
|
+
|
|
48
|
+
**Step 2: Understand. Read the `.pyi` stub before any `.py` source.** Stub paths
|
|
49
|
+
mirror source paths under `.uncoded/stubs/`:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
src/foo/bar.py → .uncoded/stubs/src/foo/bar.pyi
|
|
53
|
+
tests/test_foo.py → .uncoded/stubs/tests/test_foo.pyi
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Read the stub for every file you intend to touch or reference, including tests.
|
|
57
|
+
The stub contains imports, every signature with types, module-level assignments,
|
|
58
|
+
and class attributes. That is enough for most navigation. Skipping straight to
|
|
59
|
+
source means reading many lines to learn what the stub would have told you in
|
|
60
|
+
one. If no stub exists at the expected path, the file has no symbols indexed. In
|
|
61
|
+
that narrow case, read source directly.
|
|
62
|
+
|
|
63
|
+
**Step 3: Act.** Use `uncoded body` to read a symbol's body. Use `uncoded refs`
|
|
64
|
+
to find every reference to a symbol. Use `Edit` (with `uncoded body`'s output as
|
|
65
|
+
`old_string`) to change a symbol. With the map and stub loaded, you have the
|
|
66
|
+
exact `relative_path` and `name_path` each tool needs. Use `ClassName/method`
|
|
67
|
+
for a method and `function_name` for a top-level function. Per task:
|
|
68
|
+
|
|
69
|
+
- **Read a symbol's body.** `uvx uncoded body <name_path> --in <relative_path>`
|
|
70
|
+
prints the symbol's source text to stdout, byte-identical to disk. Returns
|
|
71
|
+
exactly the symbol. No offset arithmetic, no risk of reading too much. Its
|
|
72
|
+
output has every byte `Edit` needs as `old_string`. You need no extra `Read`
|
|
73
|
+
for partial edits. Stay on stubs for a wider sweep.
|
|
74
|
+
|
|
75
|
+
- **Find every reference to a symbol.**
|
|
76
|
+
`uvx uncoded refs <name_path> --in <relative_path>`. Prints one reference per
|
|
77
|
+
line as `file:line:col`, sorted. Grep on the name misses re-exports and adds
|
|
78
|
+
false positives from comments, strings, and attribute lookups on other types.
|
|
79
|
+
If the next move depends on the answer being complete, grep cannot give you
|
|
80
|
+
that.
|
|
81
|
+
|
|
82
|
+
- **Edit a symbol.** `uvx uncoded body <name_path> --in <relative_path>` gives
|
|
83
|
+
the exact `old_string`; then `Edit` to apply the change.
|
|
84
|
+
|
|
85
|
+
- **Rename.** `uvx uncoded refs <name_path> --in <relative_path>` enumerates
|
|
86
|
+
every site; then `Edit` at each.
|
|
87
|
+
|
|
88
|
+
- **Safely delete.** `uvx uncoded refs <name_path> --in <relative_path>` must
|
|
89
|
+
return empty; then `Edit` to remove.
|
|
90
|
+
|
|
91
|
+
## Where Read, Edit, and grep are still the right tools
|
|
92
|
+
|
|
93
|
+
The rule is about source navigation by symbol name. Outside that, Read, Edit,
|
|
94
|
+
and grep stay correct:
|
|
95
|
+
|
|
96
|
+
- Free-text or pattern search outside source: Markdown, YAML, TOML, configs,
|
|
97
|
+
commit messages, notebook JSON, fixture data.
|
|
98
|
+
- Pattern search across signatures (regex over type annotations, decorator
|
|
99
|
+
usage, alias declarations). These are not symbol-name lookups, even though
|
|
100
|
+
they sit inside source.
|
|
101
|
+
- Partial-line edits inside a symbol body, once you have retrieved it via
|
|
102
|
+
`uncoded body`.
|
|
103
|
+
- The rare stub-less Python file that needs exploratory reading.
|
|
104
|
+
|
|
105
|
+
The dispatch rule turns on the search term. A symbol name goes to the index. A
|
|
106
|
+
regex or free-text phrase goes to grep.
|