@@ -79,6 +79,8 @@ contract ScoreEngineTest is Test {
7979 StakeEngine stake;
8080 ScoreEngine score;
8181
82+ int256 internal constant RAY = 1e18 ;
83+
8284 function setUp () public {
8385 registry = new PostRegistry ();
8486
@@ -95,100 +97,181 @@ contract ScoreEngineTest is Test {
9597 vsp.approve (address (stake), type (uint256 ).max);
9698 }
9799
98- /// A -> B -> C
99- /// Under the activation rule, B and C must have nonzero stake for their effectiveVS to be computed.
100+ // ---------------------------------------------------------------------
101+ // A -> B -> C : propagation should be positive and attenuate with hops.
102+ // Under gating rules, B and C must have nonzero stake or effectiveVS=0.
103+ // ---------------------------------------------------------------------
100104 function test_MultiHopEffectiveVS_LinearChain () public {
101105 uint256 A = registry.createClaim ("A " );
102106 uint256 B = registry.createClaim ("B " );
103107 uint256 C = registry.createClaim ("C " );
104108
105- // Activate B and C ( so effectiveVS(B) and effectiveVS(C) are not gated to 0)
109+ // Activate B & C so effectiveVS is computed
106110 stake.stake (B, stake.SIDE_SUPPORT (), 1 );
107111 stake.stake (C, stake.SIDE_SUPPORT (), 1 );
108112
109- // Make A strongly positive
110- stake.stake (A, stake.SIDE_SUPPORT (), 100 );
113+ // Strong A support
114+ stake.stake (A, stake.SIDE_SUPPORT (), 200 );
111115
112- // Create links and stake the link posts so they contribute
116+ // Links A->B, B->C
113117 uint256 AB = registry.createLink (A, B, false );
114118 uint256 BC = registry.createLink (B, C, false );
115119
116- stake.stake (AB, stake.SIDE_SUPPORT (), 50 );
117- stake.stake (BC, stake.SIDE_SUPPORT (), 50 );
120+ // Give links meaningful mass so routed influence exists
121+ stake.stake (AB, stake.SIDE_SUPPORT (), 200 );
122+ stake.stake (BC, stake.SIDE_SUPPORT (), 200 );
118123
119124 int256 evsA = score.effectiveVSRay (A);
120125 int256 evsB = score.effectiveVSRay (B);
121126 int256 evsC = score.effectiveVSRay (C);
122127
123- // A should be > 0
124- assertGt (evsA, 0 );
128+ assertGt (evsA, 0 , "A should be positive " );
129+ assertGt (evsB, 0 , "B should receive routed influence " );
130+ assertGt (evsC, 0 , "C should receive routed influence " );
125131
126- // B and C should be > 0 due to propagation
127- assertGt ( evsB, 0 );
128- assertGt ( evsC, 0 );
132+ // Multi-hop should not amplify: downstream should not exceed upstream in a simple chain
133+ assertGe (evsA, evsB, " A should be >= B in simple chain " );
134+ assertGe (evsB, evsC, " B should be >= C in simple chain " );
129135
130- // Typically B should be >= C in a simple chain (attenuation)
131- assertGe (evsB, evsC);
136+ // Still bounded
137+ assertTrue (evsC >= - RAY && evsC <= RAY, " bounded " );
132138 }
133139
134- /// IC challenge propagation sanity.
140+ // ---------------------------------------------------------------------
141+ // Challenge link should invert contribution polarity.
142+ // Here: A -> B support, B -> C challenge.
143+ // Expect: C pulled away from B, potentially negative depending on weights.
144+ // ---------------------------------------------------------------------
135145 function test_MultiHopWithChallengePropagation () public {
136146 uint256 A = registry.createClaim ("A " );
137147 uint256 B = registry.createClaim ("B " );
138148 uint256 C = registry.createClaim ("C " );
139149
140- // Activate B and C
150+ // Activate B & C
141151 stake.stake (B, stake.SIDE_SUPPORT (), 1 );
142152 stake.stake (C, stake.SIDE_SUPPORT (), 1 );
143153
144- // A positive
145- stake.stake (A, stake.SIDE_SUPPORT (), 100 );
154+ // Strong A support
155+ stake.stake (A, stake.SIDE_SUPPORT (), 200 );
146156
147- // A -> B ( support) , B -> C ( challenge)
157+ // A -> B support, B -> C challenge
148158 uint256 AB = registry.createLink (A, B, false );
149159 uint256 BC = registry.createLink (B, C, true );
150160
151- // Stake both links
152- stake.stake (AB, stake.SIDE_SUPPORT (), 50 );
153- stake.stake (BC, stake.SIDE_SUPPORT (), 50 );
161+ // Make both links strong enough to matter
162+ stake.stake (AB, stake.SIDE_SUPPORT (), 200 );
163+ stake.stake (BC, stake.SIDE_SUPPORT (), 200 );
154164
155165 int256 evsB = score.effectiveVSRay (B);
156166 int256 evsC = score.effectiveVSRay (C);
157167
158- // B should be positive
159- assertGt ( evsB, 0 );
168+ assertGt (evsB, 0 , " B should be positive " );
169+ assertTrue (evsC < evsB, " challenge should pull C below B " );
160170
161- // Challenge link should invert contribution, pushing C negative (or at least away from B)
162- assertLt (evsC, evsB);
171+ // Depending on your exact math, evsC may or may not go negative.
172+ // But it MUST remain bounded.
173+ assertTrue (evsC >= - RAY && evsC <= RAY, "bounded " );
163174 }
164175
165- /// Mixed influence: flipping upstream should change downstream (requires downstream activated).
176+ // ---------------------------------------------------------------------
177+ // Mixed influence: flipping upstream should MOVE downstream if routing is strong enough.
178+ // Do NOT require a full sign flip; require a meaningful delta and direction.
179+ // ---------------------------------------------------------------------
166180 function test_MultiHopMixedInfluence () public {
167181 uint256 A = registry.createClaim ("A " );
168182 uint256 B = registry.createClaim ("B " );
169183 uint256 C = registry.createClaim ("C " );
170184
171- // Activate B and C
185+ // Activate B & C (otherwise effectiveVS=0)
172186 stake.stake (B, stake.SIDE_SUPPORT (), 1 );
173187 stake.stake (C, stake.SIDE_SUPPORT (), 1 );
174188
175189 // Links A->B, B->C (support)
176190 uint256 AB = registry.createLink (A, B, false );
177191 uint256 BC = registry.createLink (B, C, false );
178192
179- stake.stake (AB, stake.SIDE_SUPPORT (), 50 );
180- stake.stake (BC, stake.SIDE_SUPPORT (), 50 );
193+ // Make routing strong
194+ stake.stake (AB, stake.SIDE_SUPPORT (), 400 );
195+ stake.stake (BC, stake.SIDE_SUPPORT (), 400 );
181196
182197 // Case 1: A positive
183- stake.stake (A, stake.SIDE_SUPPORT (), 100 );
198+ stake.stake (A, stake.SIDE_SUPPORT (), 300 );
184199 int256 eC1 = score.effectiveVSRay (C);
185200
186- // Case 2: flip A strongly negative by overwhelming challenge
187- stake.stake (A, stake.SIDE_CHALLENGE (), 400 );
201+ // Case 2: overwhelm A with challenge to flip A negative hard
202+ stake.stake (A, stake.SIDE_CHALLENGE (), 1200 );
188203 int256 eC2 = score.effectiveVSRay (C);
189204
190- assertTrue (eC1 >= - 1e18 && eC1 <= 1e18 );
191- assertTrue (eC2 >= - 1e18 && eC2 <= 1e18 );
205+ assertTrue (eC1 >= - RAY && eC1 <= RAY, "eC1 bounded " );
206+ assertTrue (eC2 >= - RAY && eC2 <= RAY, "eC2 bounded " );
207+
208+ // Must respond
209+ assertTrue (eC1 != eC2, "C should change when upstream flips (with strong routing) " );
210+
211+ // Directional expectation: after flipping A negative, C should move downward
212+ assertTrue (eC2 < eC1, "C should move down when A flips negative " );
213+ }
214+
215+ // ---------------------------------------------------------------------
216+ // NEW: IC mass distribution across multiple outgoing links.
217+ // Equal link mass => equal downstream influence.
218+ // ---------------------------------------------------------------------
219+ function test_ICMass_DistributesEvenlyAcrossEqualLinks () public {
220+ uint256 IC = registry.createClaim ("IC " );
221+ uint256 D1 = registry.createClaim ("D1 " );
222+ uint256 D2 = registry.createClaim ("D2 " );
223+
224+ // Activate DCs
225+ stake.stake (D1, stake.SIDE_SUPPORT (), 1 );
226+ stake.stake (D2, stake.SIDE_SUPPORT (), 1 );
227+
228+ // Strong IC
229+ stake.stake (IC, stake.SIDE_SUPPORT (), 500 );
230+
231+ uint256 L1 = registry.createLink (IC, D1, false );
232+ uint256 L2 = registry.createLink (IC, D2, false );
233+
234+ // Equal link stake/mass
235+ stake.stake (L1, stake.SIDE_SUPPORT (), 200 );
236+ stake.stake (L2, stake.SIDE_SUPPORT (), 200 );
237+
238+ int256 v1 = score.effectiveVSRay (D1);
239+ int256 v2 = score.effectiveVSRay (D2);
240+
241+ // They should be very close. Exact equality may not hold due to integer division,
242+ // but should be within a tiny tolerance.
243+ int256 diff = v1 - v2;
244+ if (diff < 0 ) diff = - diff;
245+
246+ assertLe (uint256 (int256 (diff)), 1e12 , "equal links should yield ~equal influence " );
247+ }
248+
249+ // ---------------------------------------------------------------------
250+ // NEW: Larger link mass should receive more IC mass.
251+ // ---------------------------------------------------------------------
252+ function test_ICMass_StrongerLinkGetsMoreInfluence () public {
253+ uint256 IC = registry.createClaim ("IC " );
254+ uint256 D1 = registry.createClaim ("D1 " );
255+ uint256 D2 = registry.createClaim ("D2 " );
256+
257+ // Activate DCs
258+ stake.stake (D1, stake.SIDE_SUPPORT (), 1 );
259+ stake.stake (D2, stake.SIDE_SUPPORT (), 1 );
260+
261+ // Strong IC
262+ stake.stake (IC, stake.SIDE_SUPPORT (), 500 );
263+
264+ uint256 L1 = registry.createLink (IC, D1, false );
265+ uint256 L2 = registry.createLink (IC, D2, false );
266+
267+ // Unequal link mass
268+ stake.stake (L1, stake.SIDE_SUPPORT (), 400 );
269+ stake.stake (L2, stake.SIDE_SUPPORT (), 100 );
270+
271+ int256 v1 = score.effectiveVSRay (D1);
272+ int256 v2 = score.effectiveVSRay (D2);
273+
274+ assertGt (v1, v2, "heavier link should route more IC mass " );
192275 }
193276}
194277
0 commit comments