test(lang_contract): assert MEMBER_OF reverse edge (§4c bidirectional coverage)

contract_edge_defines_method asserted only the forward DEFINES_METHOD
(Class->Method) edge. The fork's reverse MEMBER_OF (Method->Class) edge —
emitted in pass_definitions.c:322 / pass_parallel.c / pass_normalize.c and
consumed by pagerank.c (member_rank_factor) — had ZERO test coverage
anywhere in the suite. Add the MEMBER_OF assertion so the function<->class
tie is locked in in both directions.

§4c investigation finding (evidence-based, refutes the plan's assumption
that a code fix was needed): the function<->class tie was ALREADY
implemented, not a merge regression. The Method-only gate
(pass_definitions.c:318) is identical in fork (3018b22:270), upstream
(34efbc0:315), and HEAD; DEFINES_METHOD is tested+passing across 9
languages (defines_method_go/rust/java/csharp/php/ruby/kotlin/ts/scala in
test_edge_types_probe.c); the documented "Go parent_class never derived"
bug is already fixed (extract_defs.c:2776-2783); and every class-scoped
callable is labeled Method with parent_class populated (push_method_def /
generic extractor / extract_rust_impl), so there is no class-scoped
Function gap to fix. Broadening the gate would change nothing. The only
real gap was the untested reverse edge, closed here.

Gate: 5981 passed / 2 failed (the 2 are the deferred B1 incremental
store-layer failures, unrelated to §4c).

Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
This commit is contained in:
Andrew Hundt
2026-06-24 19:34:23 -04:00
parent 66c6d00d55
commit 950fa19d19
+7 -2
View File
@@ -907,13 +907,18 @@ TEST(contract_edge_defines) {
PASS();
}
/* DEFINES_METHOD — Class -> Method when the method's parent_class resolves. */
/* DEFINES_METHOD — Class -> Method when the method's parent_class resolves.
* MEMBER_OF — the reverse Method -> Class edge (fork addition; consumed by
* pagerank.c member_rank_factor). Asserting BOTH directions locks in the
* function<->class tie (§4c): a class-scoped callable must link to its class
* both ways. The reverse edge previously had no test coverage anywhere. */
TEST(contract_edge_defines_method) {
static const LangFile f[] = {{"greeter.py",
"class Greeter:\n def hello(self):\n return \"hi\"\n\n"
" def bye(self):\n return \"bye\"\n\n\n"
"def main():\n g = Greeter()\n return g.hello()\n"}};
ASSERT_TRUE(edge_present(f, 1, "DEFINES_METHOD", 1)); /* Greeter.hello, Greeter.bye */
ASSERT_TRUE(edge_present(f, 1, "DEFINES_METHOD", 1)); /* Class -> Method: Greeter.hello, Greeter.bye */
ASSERT_TRUE(edge_present(f, 1, "MEMBER_OF", 1)); /* Method -> Class: reverse edge feeding PageRank */
PASS();
}