Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create helper to build public widget options for Matcher #2156

Open
wants to merge 33 commits into
base: main
Choose a base branch
from

Conversation

Myranae
Copy link
Contributor

@Myranae Myranae commented Jan 24, 2025

Summary:

Adds a function that takes a Matcher widget's full widget options and removes correct order information. Some additional shuffling logic has been added to allow shuffling to occur server-side.

It also adds this function to the widget's widget export and adds a test confirming the function works as expected.

Issue: LEMS-2761

Test plan:

  • Confirm all checks pass
  • Confirm Matcher still works as expected.

@Myranae Myranae self-assigned this Jan 24, 2025
Copy link
Contributor

github-actions bot commented Jan 24, 2025

npm Snapshot: Published

Good news!! We've packaged up the latest commit from this PR (1f1abe7) and published it to npm. You
can install it using the tag PR2156.

Example:

yarn add @khanacademy/perseus@PR2156

If you are working in Khan Academy's webapp, you can run:

./dev/tools/bump_perseus_version.sh -t PR2156

Copy link
Contributor

github-actions bot commented Jan 24, 2025

Size Change: +951 B (+0.06%)

Total Size: 1.48 MB

Filename Size Change
packages/perseus-core/dist/es/index.js 47.8 kB +1.58 kB (+3.42%)
packages/perseus/dist/es/index.js 378 kB -632 B (-0.17%)
ℹ️ View Unchanged
Filename Size
packages/kas/dist/es/index.js 39 kB
packages/keypad-context/dist/es/index.js 760 B
packages/kmath/dist/es/index.js 86.9 kB
packages/math-input/dist/es/index.js 77.6 kB
packages/math-input/dist/es/strings.js 1.79 kB
packages/perseus-editor/dist/es/index.js 688 kB
packages/perseus-linter/dist/es/index.js 22.2 kB
packages/perseus-score/dist/es/index.js 115 kB
packages/perseus/dist/es/strings.js 6.06 kB
packages/pure-markdown/dist/es/index.js 3.66 kB
packages/simple-markdown/dist/es/index.js 12.5 kB

compressed-size-action

Copy link
Collaborator

@jeremywiebe jeremywiebe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. Please check my comments as one of them (how to remove the order information) should be resolved before landing. Thanks!

packages/perseus-core/src/widgets/matcher/matcher-util.ts Outdated Show resolved Hide resolved
@Myranae Myranae marked this pull request as ready for review January 28, 2025 16:49
// @ts-expect-error - TS4104 - The type 'readonly (string | number)[][]' is 'readonly' and cannot be assigned to the mutable type '(string | number)[][]'.
indexedItems = CoreUtil.shuffle(
indexedItems,
// @ts-expect-error - TS2345 - Argument of type 'number | null | undefined' is not assignable to parameter of type 'number | RNG'.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error message was already present in the original expect error line, but I've had to split it across multiple lines here due to formatting.

@Myranae Myranae requested a review from benchristel January 30, 2025 00:46
@Myranae Myranae requested a review from jeremywiebe January 30, 2025 00:46
@Myranae Myranae requested a review from handeyeco January 30, 2025 14:07
…tcher-split

# Conflicts:
#	packages/perseus-core/src/index.ts
#	packages/perseus/src/types.ts
#	packages/perseus/src/widgets/sorter/sorter.tsx
Copy link
Member

@benchristel benchristel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool! The code looks good in general. I don't fully understand why we need to use the seeded random shuffle when getting the public options, though. It seems like sorting the "right" and "left" arrays would conceal the answer just as well, and would be simpler. EDIT: just saw Jeremy's comment. However, I am concerned that because we don't have the problemNum when shuffling serverside, the serverside shuffle is in general going to result in a different order from the clientside shuffle, so we can't rely on them being the same. Shuffling in both places creates a misleading appearance of consistency between the client and server. Overall, I still think sorting is a simpler (and equally correct) solution.

left = CoreUtil.shuffle(props.left, rng, /* ensurePermuted */ true);
}

const right = CoreUtil.shuffle(props.right, rng, /* ensurePermuted */ true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ensurePermuted = true actually leaks information about the correct answer. We are revealing that the correct answer is not the permutation sent to the client. A cheater could answer the question with better than chance accuracy by choosing some other permutation at random.

Fun fact: a variant of this type of information leak allowed the Allies to break the Enigma cipher in World War II!

A major weakness of the system, however, was that no letter could be enciphered to itself.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I see that this line was copied from the component. I think we should keep it as-is to avoid changing the UX.

packages/perseus-core/src/widgets/matcher/matcher-util.ts Outdated Show resolved Hide resolved
Comment on lines +1 to +2
/* Note(tamara): Brought over from the perseus package packages/perseus/src/util.ts file.
May be useful to bring other perseus package utilities here. */
Copy link
Contributor Author

@Myranae Myranae Feb 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The functions here are still used in other widgets as well, specifically categorizer, radio, and sorter, so I figured I should leave them in this file for now.

Comment on lines +51 to +52
expect(publicWidgetOptions.right).not.toEqual(options.right);
expect(publicWidgetOptions.left).not.toEqual(options.left);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added these expect lines to emphasize what we are looking for in this test. I think these check what we need to check regarding making sure the public widget options don't have the same order as the original ones, but please let me know if there's another test I can add for better coverage!

orderMatters: boolean;
};

// Note: Previously called cyrb128
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@benchristel Should I link to that stack overflow page in the code? Not sure about attribution within code 🤔

Comment on lines +97 to +100
left = CoreUtil.shuffle(data.left, seed, /* ensurePermuted */ true);
}

const right = CoreUtil.shuffle(data.right, seed, /* ensurePermuted */ true);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@benchristel Is there still a concern with these ensurePermuted arguments leaking data? Is that something we can fix?

@Myranae Myranae requested a review from benchristel February 6, 2025 21:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants