Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
f9cdb78
fn-slot part 2 S0: slot language rows carry the call side and the typ…
joyful-ii-V-I Oct 27, 2026
8089ced
fn-slot part 2 S1: Rust fn-valued struct fields join the (x.f)( ... )…
joyful-ii-V-I Oct 27, 2026
a1db566
fn-slot part 2 S1 arms: crate-tier store (N13) and registrar owner id…
joyful-ii-V-I Oct 27, 2026
76dc2a6
fn-slot part 2 qd: reuse nodeTextOf / rawRefAt, index owners in their…
joyful-ii-V-I Oct 27, 2026
08fccca
fn-slot part 2 qd: RustSlotWalk::text is nodeTextOf (null-safe already)
joyful-ii-V-I Oct 27, 2026
2b76679
fn-slot part 2: qschemetripcheck re-pinned once for kParserVer 247 ->…
joyful-ii-V-I Oct 27, 2026
906d827
fn-slot part 2: optremarks HOT_FILES lists src/ingest_rustslots.h (op…
joyful-ii-V-I Oct 28, 2026
1ff5068
fn-slot part 2 fix 1: arms E1-E4, Q1-Q4, N14, N15, W1 + fixture test/…
joyful-ii-V-I Oct 28, 2026
6572a6b
fn-slot part 2 fix 1 F-1 + F-2: a Rust path reaches only what its mod…
joyful-ii-V-I Oct 28, 2026
bb816c2
fn-slot part 2 fix 1 F-4: Box / Rc / Arc wrappers by the path's last …
joyful-ii-V-I Oct 28, 2026
8038fd6
fn-slot part 2 fix 1 F-5 / F-6: the Rust floors in the changelog entr…
joyful-ii-V-I Oct 28, 2026
24c3207
fn-slot part 2 fix 1 F-7 + F-8: slotTypeKeyOf( Lang ) (no longer hidd…
joyful-ii-V-I Oct 28, 2026
92fb09e
fn-slot part 2 fix 1 qd: reuse scopeLastSegment, CallResultTypes::joi…
joyful-ii-V-I Oct 28, 2026
00cc255
pyaliascallcheck: module __getattr__ arms (PY-ALIAS-SPLIT-MARKER, red…
joyful-ii-V-I Oct 28, 2026
363abcb
python pin: a module __getattr__ cannot override a def that exists
joyful-ii-V-I Oct 28, 2026
f7da53a
pyaliascallcheck: a decorated def under a module __getattr__ still pins
joyful-ii-V-I Oct 28, 2026
25e0fbf
python pin: read both dynamic markers through one list; the ?name rec…
joyful-ii-V-I Oct 28, 2026
9b9611d
feat: a posted message class names its handlers (name-key post sites,…
joyful-ii-V-I Oct 28, 2026
73f1c56
selectors: Owner.#name (a JS/TS private member) resolves as the rows …
joyful-ii-V-I Oct 28, 2026
d20ac46
defs: --defs=NAME[,NAME...] on one shared lookup (src/defslookup.h rw…
joyful-ii-V-I Oct 28, 2026
45c426f
path: inline <alts> beside from_defs=/to_defs= when the pick is not p…
joyful-ii-V-I Oct 28, 2026
239cf07
refactor: handlerrule reuses isIdentChar/trimWs, keyed site lookup, m…
joyful-ii-V-I Oct 28, 2026
08fa6b0
defs: not-found compact readings, a shaping-flag row, the ripwire.def…
joyful-ii-V-I Oct 28, 2026
00cb4ac
refactor: handlerrule drops the one-line isHandlerShaped (qd clone)
joyful-ii-V-I Oct 28, 2026
2e9eeab
defs: prove sel= only for the rows a page prints
joyful-ii-V-I Oct 28, 2026
f966224
defs: --limit/--offset page one name (refused beside several); test/d…
joyful-ii-V-I Oct 28, 2026
b2be608
fix: handlerrule keeps the Lang ratchet (Python family helper), byte …
joyful-ii-V-I Oct 28, 2026
e5fe98b
defs: gate verdicts as if/else, README flag count 193, LIMITS regen, …
joyful-ii-V-I Oct 28, 2026
00d4c21
docs: README cap inventory 287 -> 289 (the kHandlerRule* caps)
joyful-ii-V-I Oct 28, 2026
ce1ad87
compactlegendcheck: re-pin ripwire.defs/v1 to 490 on 472 B (the not-f…
joyful-ii-V-I Oct 28, 2026
066388d
docs: TUNING.md regen (capsweepcheck C: one more cap declaration, kDe…
joyful-ii-V-I Oct 28, 2026
de9d903
defs: compact <alts> readings keyed on real attributes (side=, alts_s…
joyful-ii-V-I Oct 28, 2026
6ad9ef1
path: a 2-hop --path prints its middle hop's body (PATH-HOP-BODY)
joyful-ii-V-I Oct 28, 2026
103b7c3
for: the body fold follows a thin wrapper into its callee (WRAPPER-FO…
joyful-ii-V-I Oct 28, 2026
6b06c19
for/path: one open-tag splice helper; fold clause pair in one call; g…
joyful-ii-V-I Oct 28, 2026
ae3ebc3
hopbodycheck: F2 reaches the statement-line bound directly
joyful-ii-V-I Oct 28, 2026
d29297c
regen: showcase capture 2026-10-28 (adds --defs), COMMANDS.md, deck f…
joyful-ii-V-I Oct 28, 2026
32d39e0
fn-slot part 2 fix 2 arms: S1/S2 {self} of a brace group (L-1), X1/X2…
joyful-ii-V-I Oct 28, 2026
f4cadf9
fn-slot part 2 fix 2 L-1: forEachUse {self} copies the module name be…
joyful-ii-V-I Oct 28, 2026
1d23ed1
fn-slot part 2 fix 2 L-2: a file with an out-of-tree glob (use extcra…
joyful-ii-V-I Oct 28, 2026
70c265c
README: 288 compile-time caps (readmedriftcheck L2)
joyful-ii-V-I Oct 28, 2026
25a1e58
fn-slot part 2 fix 2 arms: X7-X10 in-tree globs (mod, super, self, no…
joyful-ii-V-I Oct 28, 2026
7c1b7db
fn-slot part 2 fix 2 arm: X11 a glob inside a brace group is an out-o…
joyful-ii-V-I Oct 28, 2026
795a651
hopbodycheck: a house fail=0 accumulator (gateexitcheck (C))
joyful-ii-V-I Oct 28, 2026
707b46d
pathgapcheck: K23 arms for a write marker in a re-export hop (globals…
joyful-ii-V-I Oct 28, 2026
7c774e1
python pin: name the dynamic-write floor and match in the changelog f…
joyful-ii-V-I Oct 28, 2026
9d7bd5e
regen: showcase capture 2026-10-28 on a clean tree, COMMANDS.md
joyful-ii-V-I Oct 28, 2026
6c7b976
README: cap inventory 290 (hopbody.h adds three caps; readmedriftchec…
joyful-ii-V-I Oct 28, 2026
eb201e1
for: a ranked narrow-funnel function's callers and their callers (UPW…
joyful-ii-V-I Oct 28, 2026
181c31b
for: the ranked caller hop rides only on an error-shaped task, seeded…
joyful-ii-V-I Oct 28, 2026
5e39b4e
fix: handlerrule traces the f-string hole to its assignments, reads o…
joyful-ii-V-I Oct 28, 2026
249d76e
fix: the hrd legend says where passes= comes from (the read's line, o…
joyful-ii-V-I Oct 28, 2026
a721a0b
test: handlerrulecheck arms kill the SELF mutant (R7) and the per-rul…
joyful-ii-V-I Oct 28, 2026
e7d0aa2
refactor: handlerrule folds the per-file function index into the mess…
joyful-ii-V-I Oct 28, 2026
18f5334
test: forcallerhopcheck R arms for the ranked caller hop; changelog f…
joyful-ii-V-I Oct 28, 2026
e9e6c16
for: the ranked caller hop's posture in one helper; the task-word gat…
joyful-ii-V-I Oct 28, 2026
0158d95
defs: register --defs where three gates still miss it (F1-F3 of the r…
joyful-ii-V-I Oct 28, 2026
ac80e65
defs: <alts> prints only what changes the next step (F4-F6 of the rev…
joyful-ii-V-I Oct 28, 2026
925a33a
defslookupcheck: a same-file namesake fixture so "sel= binds that one…
joyful-ii-V-I Oct 28, 2026
ca7393a
defs: <alts> no longer claims sel= binds one alone on a sel_proven=0 …
joyful-ii-V-I Oct 28, 2026
e653ef9
defs: <alts> next= continues past page 1 (F8)
joyful-ii-V-I Oct 28, 2026
982306d
defslookupcheck: arms for the guards the fix round added; shorter <al…
joyful-ii-V-I Oct 28, 2026
77bb261
defs: lintbudgetcheck (two C casts on one line in the fixture) and pr…
joyful-ii-V-I Oct 28, 2026
5351fbb
forheadrrcheck H3: a follow_of body is not a ranked fold row (WRAPPER…
joyful-ii-V-I Oct 28, 2026
e3040e8
regen: showcase capture 2026-10-28 and COMMANDS.md on the fix-round b…
joyful-ii-V-I Oct 28, 2026
0875bfc
pagingsweepcheck: --defs joins the table of paging verbs (arm L)
joyful-ii-V-I Oct 28, 2026
7e3191e
docs: regenerate LIMITS.md, TUNING.md and README's cap count for the …
joyful-ii-V-I Oct 28, 2026
e202be1
Merge lane/on-name-v2 into lane/path-hop-body-fix1
joyful-ii-V-I Oct 28, 2026
e7dcac1
path-hop-body fix1: one edge-kind-aware body printer, route bodies on…
joyful-ii-V-I Oct 28, 2026
4d59a17
for: the ranked caller hop's review fixes: language-neutral whole-wor…
joyful-ii-V-I Oct 28, 2026
b8d4382
path-hop-body fix1: thinDelegate's statement count in its own helper;…
joyful-ii-V-I Oct 28, 2026
d23bb05
path-hop-body fix1: ack the three intended internal contract changes
joyful-ii-V-I Oct 28, 2026
85ad94f
path-hop-body fix1: regenerate the cap inventory (kWrapperFollowMax, …
joyful-ii-V-I Oct 28, 2026
449261e
path-hop-body fix1: route bodies stay off inside a --for graph-verb b…
joyful-ii-V-I Oct 28, 2026
8c66c90
for: the ranked seed's string scan shares one set of scanner options;…
joyful-ii-V-I Oct 28, 2026
6a4cd31
test: the rankword fixture's one-word row also holds "error", pinning…
joyful-ii-V-I Oct 28, 2026
62e7231
for: the ranked seed reuses routeLower and splits into small helpers;…
joyful-ii-V-I Oct 28, 2026
aa13b25
test: de-flake memguardcheck B6b (readdir-order dependent) and pargat…
joyful-ii-V-I Oct 28, 2026
5dade5d
for: forLiteralHoldsTaskWords reads a literal's words through the tas…
joyful-ii-V-I Oct 28, 2026
ba155d1
test: memguardcheck B21 asks whether the stream finished, not how man…
joyful-ii-V-I Oct 28, 2026
d986467
path-hop-body fix2: arms R6-R9 pin the edge-row hedge, per-body cap a…
joyful-ii-V-I Oct 28, 2026
a72a512
path-hop-body fix2: generate the R6-R8 route fixtures from the route …
joyful-ii-V-I Oct 28, 2026
f76dcb5
Merge lane/ci-flakes-3 into integration/train-41 (test-only: memguard…
joyful-ii-V-I Oct 28, 2026
c0314ec
Merge lane/defs-lookup into integration/train-41 (Owner.name selector…
joyful-ii-V-I Oct 28, 2026
530d652
Merge lane/py-split-marker into integration/train-41 (globals()/setat…
joyful-ii-V-I Oct 28, 2026
72832bc
Merge lane/fn-slot-2 into integration/train-41 (Rust fn slots S0+S1)
joyful-ii-V-I Oct 28, 2026
55263b4
Merge lane/path-hop-body-fix1 into integration/train-41 (route bodies…
joyful-ii-V-I Oct 28, 2026
a98489d
Merge lane/upward-2hop into integration/train-41 (ranked 2-hop caller…
joyful-ii-V-I Oct 28, 2026
c8b4981
train 41: versions above every placeholder, qschemetrip re-pin, gener…
joyful-ii-V-I Oct 28, 2026
fd75f9c
train 41: ONE showcase regen from the composed binary (c8b49812)
joyful-ii-V-I Oct 28, 2026
f0d4db4
train 41: split path-route-body.md's second heading into its own frag…
joyful-ii-V-I Oct 28, 2026
035aa39
train 41: docs/COMMANDS.md regenerated from the new capture
joyful-ii-V-I Oct 28, 2026
251ac97
train 41: cppqualcheck --uses=readWholeFile 38 -> 39 (upward-2hop's s…
joyful-ii-V-I Oct 28, 2026
066bdce
path: <alts> never lists a definition a <bodies of=hops|route> body p…
joyful-ii-V-I Oct 29, 2026
94c46dc
changelog: <alts> skips body-printed definitions; drop internal revie…
joyful-ii-V-I Oct 29, 2026
af8fc25
qd: ack the two path-hop-body cumulative gating rows (pathText cx 29-…
joyful-ii-V-I Oct 29, 2026
d6b89bc
defs-lookup: --path <alts> prints only rows whose sel= was computed (…
joyful-ii-V-I Oct 29, 2026
fd8cf7d
fn-slot-2: a bare callee the function binds is never the in-tree regi…
joyful-ii-V-I Oct 29, 2026
4088236
test: hopbodycheck X2 skips cleanly without xmllint (CodeRabbit 44084…
joyful-ii-V-I Oct 29, 2026
171c574
test: writtenspellingcheck binds both callees of the bare #dispatch u…
joyful-ii-V-I Oct 29, 2026
eee47f9
upward-2hop: a yes/no question without a ? is a question (CodeRabbit …
joyful-ii-V-I Oct 29, 2026
492d148
cli: drop the dead --defs row from kShapingVerbs (CodeRabbit review 5…
joyful-ii-V-I Oct 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/pargates-shard-weights.json
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@
"greptiercheck.sh": 16.6,
"guardmsgcheck.sh": 1.1,
"handoffcheck.sh": 12.6,
"handlerrulecheck.sh": 3.0,
"hasacheck.sh": 2.7,
"hazardpatterncheck.sh": 5.2,
"headsnapcachecheck.sh": 19.9,
Expand Down
6 changes: 5 additions & 1 deletion .ripwire_quality_acks

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -982,9 +982,9 @@ Full retrieval tables — including the MRR figures behind the router numbers ab
## What it answers

<details>
<summary><b>192 long flags</b> across seven families, plus the MCP server — and <code>--help-task</code> names the ONE command a task wants, or abstains honestly when the evidence is too thin</summary>
<summary><b>193 long flags</b> across seven families, plus the MCP server — and <code>--help-task</code> names the ONE command a task wants, or abstains honestly when the evidence is too thin</summary>

Around the core sit 192 long flags advertised in `--help`, across seven families — plus an MCP
Around the core sit 193 long flags advertised in `--help`, across seven families — plus an MCP
server, so a coding agent can call any of them mid-task instead of grepping and reading whole files.
`--help` prints one line per flag (~4.5K tokens); `--help=--FLAG` prints that flag's full entry with
every caveat, `--help=SECTION` one family, and `--help=all` the whole catalog.
Expand Down Expand Up @@ -2120,9 +2120,9 @@ wrong, and it has. These are the results that say so, all in-tree, all published
### In the tests

<details>
<summary><b>726 gate scripts</b>, five contracts no unit test can hold, and the house rule: write the gate before the code it measures</summary> <!-- gatecount -->
<summary><b>729 gate scripts</b>, five contracts no unit test can hold, and the house rule: write the gate before the code it measures</summary> <!-- gatecount -->

`test/regression.sh` names **726 gate scripts** and is the authoritative list; <!-- gatecount -->
`test/regression.sh` names **729 gate scripts** and is the authoritative list; <!-- gatecount -->
`python3 test/pargates.py . ./build/ripwire -j 6` runs the same set in parallel. On top of them sit the
contracts that do not fit a unit test: two runs byte-identical, warm output identical to cold, output
that pipes clean through `xmllint --noout`, a sanitizer build with `-fno-sanitize-recover=all`, and a
Expand Down Expand Up @@ -2684,7 +2684,7 @@ identity of the index, and says which one is at fault.

### 5. Command families

The `--help` output groups 192 long flags advertised in `--help` into seven families. The `--help=`
The `--help` output groups 193 long flags advertised in `--help` into seven families. The `--help=`
column below is the argument that prints one family: `ripwire --help=navigate`. `ripwire
--help=--FLAG` prints one flag's full text — the caveats, the units, what it refuses and why.
`ripwire --help=all` is the whole catalog, about 46,000 tokens.
Expand Down Expand Up @@ -2878,7 +2878,7 @@ python3 test/pargates.py . ./build/ripwire -j 6
A new gate script must be added to `test/regression.sh` in the same change. The gate
`test/manifestcheck.sh` enforces this rule.

Another gate derives the cap inventory. The tool has 287 compile-time caps and 7 ranking parameters.
Another gate derives the cap inventory. The tool has 298 compile-time caps and 7 ranking parameters.
`docs/LIMITS.md` lists each cap, its value, and whether the file discloses a truncation when the cap
fires, and `python3 docs/limits_build.py --check` proves that list against `src/`. `docs/TUNING.md`
lists the measured cost of each cap.
Expand Down
18 changes: 18 additions & 0 deletions changelog.d/ci-flakes-3-memguard-b6b.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
### Fixed — three flaky gate arms: memguardcheck (B6b, B21) and pargatescheck (I control)

None is a product change; each arm depended on something the gate did not control.

- `test/memguardcheck.sh` (B6b): the arm sent a `find_symbol a_02` as the second MCP call against an index cut by the crawl
trip at entry 30. Which fixture files survive that cut is the filesystem's directory order (the crawl does not sort before it
stops): on macOS `a/f02.c` is kept; on a Linux runner whose directory order places it later, `a_02` is outside the cut index and
the answer is a not-found error, which carries no `_memory_stop` envelope field, so the arm read an empty string (red on main
and on both train-40 PR runs, ubuntu release shard 4/4, green on rerun). The follow-up call is now `grep`, whose answer is a
result on any partial index, so the arm checks the same thing (a later answer from the same cut index keeps the disclosure) on
every filesystem; the `find_symbol` call stays as a third probe asserted on the shape it returns, with a NOTE line when it fell outside the cut.
- `test/pargatescheck.sh` (I control): the control copy that puts the old "wait, then look at the stop" loop back waited 0.5 s
before looking, leaving 0.2 s for the probe gate to start and pass its 0.3 s mark; at load average 9 to 13 it failed three
runs of three on unmodified main. The control's first wait is now 3.0 s; the ordering defect it models is unchanged.
- `test/memguardcheck.sh` (B21): the arm required the refusal to return within 4 s of a 6 s git-log stream, but the shim's 60
spawned sleeps stretch that stream on a busy host and the refusal took 5 s at load average 13 to 19. The arm now asks what a
join would do, which is wait for the stream's end: the shim writes a marker after its last line and the refusal must return
without it.
11 changes: 11 additions & 0 deletions changelog.d/defs-lookup-verb.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
### Added — `--defs=NAME[,NAME…]`: which definitions a name binds, with the spelling that picks each one alone

One call answers "which definitions does this name bind?" for up to 16 names in one index load. Each definition group (a C-family
prototype with the definition it declares is one; a TypeScript overload with its implementation is one) is a row with its
owner-qualified name, kind, `file:line`, language, `class=source|test` and its distinct graph callers (a floor), plus `sel=`: a
spelling every symbol verb accepts that the lookup re-resolved and proved binds that definition and nothing else (`name`,
`file:name`, `file:Owner.name`, then the `@file:line` seed; `sel_proven="0"` when none does). Source rows come first, then by
callers. A JSON/YAML key or a markdown heading of the same name is counted as `data_defs=` and never listed as code; a definition
the parser does not model (an assignment, `define_method`, `setattr`) is not one. More than 16 rows page with `--offset`; a single
name that binds nothing answers with the shared "not found" refusal. `--json` gives the same rows. The lookup lives in one header
(`src/defslookup.h`, `rw::lookupDefs`), reusing the definition-group rule the callers/impact tables use.
13 changes: 13 additions & 0 deletions changelog.d/for-wrapper-follow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
### Added — the `--for` body fold follows a one-line wrapper into the function it calls

When a body the `--for` fold serves is a thin delegator (one proven callee, no other call, at most 3 statement lines, such as
`fetch` returning `this.#dispatch(...)`), the callee's body is now printed right after it as `<b follow_of="fetch">`, up to two
levels (`handle -> fetch -> #dispatch`). A callee bound by name alone, a body with a second call or a fourth statement line, and
a body the answer already carries are never followed. The followed bodies ride outside the fold's `budget_bytes=`, each whole up
to 4000 bytes (a longer one is cut and says so). `RIPWIRE_NO_HOP_BODY=1` turns it off.

Measured: hono's default `--for "How does a request flow from app.fetch to a handler's Response?"` now carries `#dispatch`'s body
(router match, Context, the one-handler fast path, `compose`, error handling) after `fetch` (+1.9 KB). Over the in-sample tables
the follow fires on 3 of 163 S1 rows (+4.3 KB, all already complete), 2 of 39 MF1-DEV rows (+3.0 KB; ninja `Plan::AddTarget ->
AddSubTarget`) and 3 of 56 LARGE-DEV rows (+5.7 KB, one body cut at the 4000-byte guard); no row loses an item.
Gate: `test/hopbodycheck.sh`.
29 changes: 29 additions & 0 deletions changelog.d/message-handler-rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
### Added — a posted message class names its handlers (`via="name-key"`, `<handler_rule>` on `--path`)

A Python message framework dispatches by a name the message's class carries: textual's `Message.__init_subclass__` writes
`cls.handler_name = f"on_{name}"`, and the pump looks the handler up with `cls.__dict__.get( method_name )`. That lookup takes a
parameter, so it can name every `on_*` method. The class is known where the message is posted, though:
`self.post_message( Button.Pressed( self ) )` names `Button.Pressed`, and its handler is `on_button_pressed`. Such a post site
is now a name-key hop to the methods of that name, with `cands=K` beside it. The hop shows in `--impact`
(`reaches_hedged_via="name-key"`), in the `--path` hedged bridge (at most 16 candidates), and in `near_sink`, where a
dispatched handler is now `why="declined:N" via="name-key"`, no longer `why="external"`. When `from=` is a poster and the
posted classes name a `to=` handler, a reachable="0" `--path` also prints `<handler_rule>`. It holds the rule's `p=` and its
spelling, the functions that read the handler-name attribute with the method each one passes it to (textual:
`MessagePump._on_message` passes it to `MessagePump._get_dispatch_methods`, the MRO walk), and the posted classes, widest
first. The handler definitions are listed only when there are at most 16 of them. Above that, the answer gives a count and
`next=`, never a cut list.

The rule is read from the repo's own source, never from a framework list. It needs a Python `__init_subclass__` with ONE
top-level write `cls.A = f"P{v}"` (not under an `if`/`else`/`for`/`while`/`try`/`match`), where every assignment of the local
`v` calls a camel-to-snake converter (a body holding the `[a-z][A-Z]` regex and `.lower()`) on `__qualname__`'s last two parts
or on `cls.__name__`. A `{namespace}_` branch reads a `namespace="x"` class keyword. A class takes the NEAREST rule base (the
most derived one); a class below an intermediate class whose own `__init_subclass__` also writes `cls.A` is not named, and two
unrelated rule bases decline. A base written by name that several classes carry binds only through the deriving file's own
import. Readers and posters are kept per rule. A post site is a call to a method of a class that reads `.A` outside test
paths, with a first argument that constructs a subclass: `X( … )`, `self.X( … )`, `Owner.X( … )` or `module.X( … )`.

What it does NOT mean: the name is matched, not traced. Which candidate runs depends on the receiving object's class, and the
index does not decide that. A hop is never counted in `reaches=`, `reachable=` or `hops=`. The floors are: a variable
argument (`msg = Tick(); post_message( msg )`); a factory (`events.Click.from_event( … )`); a converter or qualname cut of any
other shape; `@on( Message )`-decorated handlers (already shown as value refs); and a class body's own `handler_name =`
(the rule runs after the class body and overwrites it). Gate: `test/handlerrulecheck.sh`.
9 changes: 9 additions & 0 deletions changelog.d/path-hop-body-fixes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
### Fixed — the middle-hop body and the wrapper follow say what they prove

- A middle hop reached by name (`obj.process(x)` with two `process` definitions) prints its body with `via="name" cands="2"` on
the `<b>`, never as if it were the proven callee.
- A `--for` wrapper follow needs a function or method whose text holds exactly one call site of any kind, that call its last
statement: a declined, external or undefined call beside it, logic around it, a loop aggregator or a class field initializer
is no wrapper. A C `*out = v;` line counts as a statement; a Python docstring does not.
- `follow_of=` names the wrapper as its row does (`ChildRunner.launch`), and one answer follows at most 3 bodies; past that
`<follow_cut n= next=>` counts the wrappers left and names the first callee.
16 changes: 16 additions & 0 deletions changelog.d/path-hop-body.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
### Added — a short `--path` answer prints the body of its middle hop

A reached `--path` (and MCP `path_between`) whose chain has 2 hops now prints, after its hop rows, the body of its
middle hop inside `<bodies of="hops">`: the same `<b>` element `--expand` prints, without callee rows. The endpoints never get a
body. Each body is whole up to 4000 bytes; a longer one is cut at a line end and says so on the element (`truncated="1"
lines="1-K/T" next=` the call that serves the rest). A chain of more hops prints no body, and its root carries
`next="--expand=…"` naming the first middle hop. Inside a `--for` answer's graph-verb block on the CLI, a middle hop whose body the
answer already prints is not printed twice (MCP `for` has no served set to compare: a known divergence). `RIPWIRE_NO_HOP_BODY=1` turns it off.

Why: `--path=fetch,compose` on hono named `Hono.fetch -> Hono.#dispatch -> compose` and stopped there, while the whole request
flow (path extraction, router match, Context, the one-handler fast path, compose, error handling) lives in `#dispatch`'s body.
Measured on the 163-row S1 replay: hono-12 goes from 0 to 6 of 7 required items (✗ -> ◐ by Rule C, ✗ -> ✓ legacy), 0 rows
lower; 9 of the 15 `--path` rows change, +3.1 KB in total (hono-12 +2.1 KB, kysely-14 +0.5 KB, six longer chains +~90 B of
`next=` each). The 2-hop gate is measured: 3 hops would add 1.6 KB on one already-complete row, 4 hops 13 KB on two more, and no
item. On LARGE-DEV one `--for` graph-verb path block gains a middle body (zed `get_any_active_multi_workspace`, +1.0 KB) and seven
gain only `next=`. Gate: `test/hopbodycheck.sh`.
9 changes: 9 additions & 0 deletions changelog.d/path-inline-alternatives.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
### Changed — `--path` lists the other definitions of an endpoint whose pick is not provably unique

`--path=fetch,compose` on hono printed `from_defs="7"`, bound one `fetch` and named none of the others, so an agent had to guess a
`file:name` spelling and retry. When an endpoint's name binds two or more definition groups, the answer (CLI and MCP
`path_between`) now ends with `<alts side="from|to" of=NAME>`: one compact row per other definition with `p=`, `class=` and a
pasteable `sel=`, and `decl_only="1"` when the row has no body (a header declaration or an interface contract). Up to 16 rows;
past that `alts_shown=K defs=N next=--defs=NAME` pages the rest. A definition the answer already prints (the bound one, the
endpoint of a listed `<pair>`, or a function whose body sits in `<bodies>`) is not listed again, and a C prototype no `#include` ties to a definition is not a second candidate
(the rule `from_defs`/`to_defs` use), so an endpoint that binds one definition, or a `*` glob endpoint, adds nothing.
13 changes: 13 additions & 0 deletions changelog.d/path-route-body.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
### Added — an unreached `--path` prints the bodies of the route it names

A `reachable="0"` `--path` (and MCP `path_between`) that names a route it could not trace — the bridge rows (a poster, the queue
consumer, the dispatcher) and the `<handler_rule>` readers — now prints those functions' bodies in `<bodies of="route"
proven="0">`: the bridge rows within 2 hops of `from=` (never `to=`), then the readers, at most 4 bodies (past that `capped="1"`
and `next=` the first one left out), each whole up to 4000 bytes. Every body is a hedge: one under a crossing carries that hop's
`via=` and `cands=` (`via="queue" cands="3"`), a reader's carries `via="name-key"`, and none of it enters `reachable=` or `hops=`.
Inside a `--for` answer's graph-verb block it stays off (that answer serves its own bodies; the one in-sample fire there, a
vscode `--for`, added 7.7 KB that named nothing the question asked). `RIPWIRE_NO_HOP_BODY=1` turns it off.

Why: textual's `--path=post_message,on_*` named `post_message -> _process_messages_loop -> _dispatch_message` and the reader
`_on_message`, but the answer to "how does a posted message reach its handler" lives in their bodies (the queue put, the loop's
get, the bubble to `_parent`). Measured: textual-11 goes from 4 to 6 of 6 required items by Rule C (◐ -> ✓), +7.0 KB.
7 changes: 7 additions & 0 deletions changelog.d/private-member-selectors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
### Fixed — a JS/TS private member resolves as the rows print it: `Hono.#dispatch`

Train 40 started printing owner-qualified names (`n="Hono.#dispatch"`) on `--path`, `--callers` and `--callees` rows, but pasting
one back failed: `--callees=Hono.#dispatch` answered "not found" and `--path=Hono.#dispatch,compose` exited 1 on hono, because the
spelling splitter read the `#` as Ruby's `Class#method` separator and saw an empty segment. A `#` that starts a segment is now part
of the name, so `Owner.#name` and `file:Owner.#name` bind the one private member they name; Ruby `Cart#total` reads as before, and
`Owner.name` without the `#` still names nothing. Found while grading `--path` answers on hono. Gate: `test/writtenspellingcheck.sh` (1b).
11 changes: 11 additions & 0 deletions changelog.d/py-alias-split-marker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
### Fixed — a module `__getattr__` no longer withholds a renamed-import call to a function the module defines

A Python call through a renamed import (`from m import f as g; g()`) stayed undecided whenever `m` defined a module-level
`__getattr__` (PEP 562), as if `__getattr__` could replace `m.f`. It cannot: Python consults it only for a name the module
does not bind. The call now binds `m.f` as a proven edge in that case too, and a module `__getattr__` in the calling file no
longer withholds it either. It still stays undecided when `f`'s definition in `m` sits inside an `if`, `try`, `with`, `match` or
loop at module scope (it may not run, and `__getattr__` then answers), when `m` writes its namespace dynamically (`globals()[...]`,
`setattr(...)`), and in every case listed for the renamed-import change. Known limit, unchanged: a module that rebinds a
name some other way (`vars()[...]`, `locals()[...]`, `exec(...)`, `__dict__[...]`, `sys.modules[__name__].name = ...`) is not
recognized as a dynamic write, so a pin into it can be wrong, now also in files that define `__getattr__`. On CPython's standard library this restores 11
call sites (`re.sub`, `re.escape`, `re.compile`, `platform.system`, `platform.architecture`). Gate: `test/pyaliascallcheck.sh`.
Loading
Loading