Without knowing how many people have read this question I don't know whether or not this information is useful to others. Would it be possible to put a view count on the thread like the reply count?
Anyway, I finally figured out how to execute a rule for each row in a repeating table and thought I'd post the answer in case anyone else is interested.
I created an integer field idx to use as the position of the repeating row, and to that field I added a rule with the above listed actions to set the values of the web service and execute it. I figured that I'd set the value of idx to 1, use it to get the right set of person values, increment idx and do it again until idx > count(Person). But it was a bit tricky getting the value of idx to re-evaluate each time.
In the place of "position() = 1" in the rule actions above I used "number(../../my:gpFormVariables/my:idx)". You must use number(), and put the full relative path of idx in it to get it to reevaluate each time. Just choose Person/DisplayName, check Edit XPath, then type "[number(full relative xpath to your index field)]" right after Person and before /.
set a fields value: groupName = concat(DocLibrary, " Read")
set a fields value: userName = Person[number(../../my:gpFormVariables/my:idx)]/pc:DisplayName
set a fields value: userLoginName = Person[number(../../my:gpFormVariables/my:idx)]/pc:AccountId
query using a data connection: AddUserToGroup
I added another action to increment idx:
set a fields value: idx = idx + 1
and then added a condition to the rule so that it would only execute for the number of rows in the repeating table:
idx <= count(../../my:gpApprovers/pc:Person)
Then I added a rule to my 'submit' button:
set a fields value: idx = 1
Works like a champ, but is subject to the rule of 16 ... it would not run more than 16 times because of Infopath's built in rule to prevent infinite loops.