Summary
Two things #97 found while collapsing duplicate scopes (#96) and left alone on purpose, because both need a fact nobody has yet: what Roblox actually stores when it is sent a payload it can normalise.
1. Two operation sets on one scope type are still two entries
asset:read next to asset:write in the same key produces two ScopeDef entries with identical targetParts and one operation each. Semantically that is the union, so merging them into {scopeType: "asset", targetParts: [...], operations: ["read", "write"]} is probably correct and would shrink every payload this tool sends.
"Probably" is the problem. #96 collapsed exact duplicates, which is safe because the entry is byte-identical; merging different operation sets is a normalisation, and the merged shape is one this tool has never sent. The way to settle it is to create a key both ways against the live API and read back what introspect reports.
2. The create-time verification counts entries instead of comparing them
rbx apikey create verifies what Roblox stored by comparing the number of scope entries it sent against the number that comes back. So any normalisation on Roblox's side — collapsing, reordering, splitting — reads as drift, on a key that was just created correctly.
Duplicates were the trigger that made this reachable, and #96 removed them, so nothing hits it today. The check is still counting rather than comparing, which means it will fire again the first time Roblox changes how it stores something, and the report will name drift rather than "the payload came back in a different shape".
Comparing sets of (scopeType, targetParts, operation) triples would be both stricter and quieter: it catches a scope that genuinely did not land, and it stops caring about arrangement.
Why they belong together
Both are about the same unknown, and one live-API session answers both: create a key with two operation sets on one scope type, read back what Roblox stored, and the answer decides whether item 1 is a merge or a mistake and gives item 2 its comparison. testenv/ exists for exactly this kind of question.
Re-filed from #101 when the repository history was reset for 0.1.0. Issue and PR numbers referenced above belong to the previous numbering and no longer resolve; the reasoning does not depend on them.
Summary
Two things #97 found while collapsing duplicate scopes (#96) and left alone on purpose, because both need a fact nobody has yet: what Roblox actually stores when it is sent a payload it can normalise.
1. Two operation sets on one scope type are still two entries
asset:readnext toasset:writein the same key produces twoScopeDefentries with identicaltargetPartsand one operation each. Semantically that is the union, so merging them into{scopeType: "asset", targetParts: [...], operations: ["read", "write"]}is probably correct and would shrink every payload this tool sends."Probably" is the problem. #96 collapsed exact duplicates, which is safe because the entry is byte-identical; merging different operation sets is a normalisation, and the merged shape is one this tool has never sent. The way to settle it is to create a key both ways against the live API and read back what
introspectreports.2. The create-time verification counts entries instead of comparing them
rbx apikey createverifies what Roblox stored by comparing the number of scope entries it sent against the number that comes back. So any normalisation on Roblox's side — collapsing, reordering, splitting — reads as drift, on a key that was just created correctly.Duplicates were the trigger that made this reachable, and #96 removed them, so nothing hits it today. The check is still counting rather than comparing, which means it will fire again the first time Roblox changes how it stores something, and the report will name drift rather than "the payload came back in a different shape".
Comparing sets of
(scopeType, targetParts, operation)triples would be both stricter and quieter: it catches a scope that genuinely did not land, and it stops caring about arrangement.Why they belong together
Both are about the same unknown, and one live-API session answers both: create a key with two operation sets on one scope type, read back what Roblox stored, and the answer decides whether item 1 is a merge or a mistake and gives item 2 its comparison.
testenv/exists for exactly this kind of question.Re-filed from #101 when the repository history was reset for 0.1.0. Issue and PR numbers referenced above belong to the previous numbering and no longer resolve; the reasoning does not depend on them.