From 950fa19d193b4fcbdf3e9daf7d58bb23a6fe8e30 Mon Sep 17 00:00:00 2001 From: Andrew Hundt Date: Wed, 24 Jun 2026 19:34:23 -0400 Subject: [PATCH] =?UTF-8?q?test(lang=5Fcontract):=20assert=20MEMBER=5FOF?= =?UTF-8?q?=20reverse=20edge=20(=C2=A74c=20bidirectional=20coverage)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- tests/test_lang_contract.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/test_lang_contract.c b/tests/test_lang_contract.c index f29e7d894..3d46d0310 100644 --- a/tests/test_lang_contract.c +++ b/tests/test_lang_contract.c @@ -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(); }