[AbsoluteValue] PR4 - scoring#3351
Conversation
🗄️ Schema Change: Changes Detected
|
🛠️ Item Splitting: No Changes ✅ |
|
Size Change: +113 B (+0.02%) Total Size: 490 kB
ℹ️ View Unchanged
|
npm Snapshot: PublishedGood news!! We've packaged up the latest commit from this PR (2c8e427) and published it to npm. You Example: pnpm add @khanacademy/perseus@PR3351If you are working in Khan Academy's frontend, you can run the below command. ./dev/tools/bump_perseus_version.ts -t PR3351If you are working in Khan Academy's webapp, you can run the below command. ./dev/tools/bump_perseus_version.js -t PR3351 |
There was a problem hiding this comment.
LGTM — straightforward extension of existing graph scoring patterns to support absolute-value graphs.
Extended reasoning...
Overview
This PR adds absolute-value graph support to the interactive graph scoring system across 5 files: a new getAbsoluteValueCoefficients function in kmath, its type export, an AbsoluteValueGraphCorrect type in the data schema union, scoring logic in score-interactive-graph.ts, and comprehensive tests.
Security risks
None. This is pure math/scoring logic with no I/O, auth, or external interactions.
Level of scrutiny
Low scrutiny warranted. The changes mechanically follow the exact same pattern used for quadratic and sinusoid graph scoring. The coefficient computation is straightforward: Math.abs(rise/run) with sign determined by whether p2 is above or below the vertex, which correctly handles points on either arm of the V. The scoring branch mirrors the quadratic branch (compute coefficients, compare with approximateDeepEqual).
Other factors
- Good test coverage: 6 tests covering invalid input (undefined guess, missing coords), wrong answer, exact match, symmetry (point on other arm), and direction mismatch (upward vs downward).
- The new
AbsoluteValueGraphCorrecttype is correctly added to thePerseusGraphCorrectTypeunion, which is the type used byPerseusInteractiveGraphRubric.correct. - The
PerseusGraphTypeAbsoluteValuetype already existed in the data schema, so this PR just adds the scoring support. - PR description is empty, but the code is self-explanatory given the established patterns.
ivyolamit
left a comment
There was a problem hiding this comment.
Changes looks logical to me 👍🏼
Everything is AI ## Summary: This is part of a series of PRs as defined in the first PR: -▶️ [Perseus#3346: PR implementation guide](#3346) - [Perseus#3348: PR1 - type definitions and schema](#3348) - [Perseus#3349: PR2 - state management](#3349) - [Perseus#3350: PR3 - rendering & accessibility](#3350) - [Perseus#3351: PR4 - scoring](#3351) - [Perseus#3352: PR5 - editor support](#3352) - [Perseus#3380: Convert todo into a long-term doc](#3380) Initial implementation experiment is [Perseus#3304](#3304). Issue: LEMS-3347 Author: handeyeco Reviewers: claude[bot], handeyeco, ivyolamit, SonicScrewdriver Required Reviewers: Approved By: ivyolamit Checks: ⏭️ 1 check has been skipped, ✅ 10 checks were successful Pull Request URL: #3346
Everything is AI ## Summary: This is part of a series of PRs as defined in the first PR: - [Perseus#3346: PR implementation guide](#3346) -▶️ [Perseus#3348: PR1 - type definitions and schema](#3348) - [Perseus#3349: PR2 - state management](#3349) - [Perseus#3350: PR3 - rendering & accessibility](#3350) - [Perseus#3351: PR4 - scoring](#3351) - [Perseus#3352: PR5 - editor support](#3352) - [Perseus#3380: Convert todo into a long-term doc](#3380) Initial implementation experiment is [Perseus#3304](#3304). Issue: LEMS-3347 --- Add type definitions and schema for absolute-value graph type Adds the foundational type scaffolding needed to support an absolute-value graph in the Interactive Graph widget. This is a pure additive change — no runtime behavior is altered and all existing tests continue to pass. Changes: - data-schema.ts — Adds PerseusGraphTypeAbsoluteValue (type: "absolute-value", coords, startCoords) and includes it in the PerseusGraphType union. - interactive-graph-widget.ts — Registers parsePerseusGraphTypeAbsoluteValue with parsePerseusGraphType so the new type round-trips through the parser. - types.ts — Adds AbsoluteValueGraphState (mirrors SinusoidGraphState: vertex + arm point) and adds it to the InteractiveGraphState union. - interactive-graph-ai-utils.ts — Adds AbsoluteValueGraphOptions and AbsoluteValueUserInput types and wires them into getGraphOptionsForProps / getUserInput to satisfy exhaustiveness checks. - Stubs out "absolute-value" cases with throw new Error("Not implemented") in initializeGraphState, mafsStateToInteractiveGraph, renderGraphElements, and getEquationString to keep TypeScript exhaustiveness errors clear until subsequent PRs fill in the implementation. - Adds "absolute-value" to the mergeGraphs switch and shouldShowStartCoordsUI in the editor to satisfy exhaustiveness checks there as well. Author: handeyeco Reviewers: claude[bot], handeyeco, ivyolamit, SonicScrewdriver Required Reviewers: Approved By: ivyolamit Checks: ✅ 10 checks were successful, ⏭️ 1 check has been skipped Pull Request URL: #3348
Everything is AI ## Summary: This is part of a series of PRs as defined in the first PR: - [Perseus#3346: PR implementation guide](#3346) - [Perseus#3348: PR1 - type definitions and schema](#3348) -▶️ [Perseus#3349: PR2 - state management](#3349) - [Perseus#3350: PR3 - rendering & accessibility](#3350) - [Perseus#3351: PR4 - scoring](#3351) - [Perseus#3352: PR5 - editor support](#3352) - [Perseus#3380: Convert todo into a long-term doc](#3380) Initial implementation experiment is [Perseus#3304](#3304). Issue: LEMS-3347 --- Implements the full state pipeline for the absolute-value graph: initialization, reducer transitions, serialization, and test infrastructure. Depends on PR 1. No rendering yet — the renderGraphElements stub from PR 1 remains in place. Changes: - initialize-graph-state.ts — Replaces the PR 1 stub with a real initializeGraphState case. Adds getAbsoluteValueCoords(graph, range, step): returns graph.coords if set, then graph.startCoords, then normalized defaults [[0.5, 0.5], [0.75, 0.75]] (same pattern as sinusoid/quadratic). Note: currently unexported — PR 5 exports it for editor use. - interactive-graph-action.ts — Adds actions.absoluteValue.movePoint by reusing the shared movePoint action factory (same approach as sinusoid). - interactive-graph-reducer.ts — Adds a case "absolute-value" in doMovePoint that snaps/bounds the destination, then rejects the move if the two points would share the same x-coordinate (slope would be undefined). - interactive-graph-state.ts — Adds a branch in getGradableGraph() that serializes AbsoluteValueGraphState back to PerseusGraphTypeAbsoluteValue for scoring. - mafs-state-to-interactive-graph.ts — Replaces the PR 1 stub with a real case that maps state coords back to the graph type for live interaction (e.g. equation display). - interactive-graph-question-builder.ts — Adds withAbsoluteValue(options?) builder method and AbsoluteValueGraphConfig class so test fixtures can construct absolute-value questions. Author: handeyeco Reviewers: claude[bot], ivyolamit, SonicScrewdriver Required Reviewers: Approved By: ivyolamit Checks: ⏭️ 1 check has been skipped, ✅ 10 checks were successful Pull Request URL: #3349
16655f3 to
442bfca
Compare
Everything is AI ## Summary: This is part of a series of PRs as defined in the first PR: - [Perseus#3346: PR implementation guide](#3346) - [Perseus#3348: PR1 - type definitions and schema](#3348) - [Perseus#3349: PR2 - state management](#3349) -▶️ [Perseus#3350: PR3 - rendering & accessibility](#3350) - [Perseus#3351: PR4 - scoring](#3351) - [Perseus#3352: PR5 - editor support](#3352) - [Perseus#3380: Convert todo into a long-term doc](#3380) Initial implementation experiment is [Perseus#3304](#3304). Issue: LEMS-3347 --- Implement rendering and accessibility for absolute-value graph type Adds the visual component, screen reader strings, equation display, and unit tests for the absolute-value graph. Depends on PR 1 + PR 2. After this PR the graph is fully interactive and renderable. Changes: - graphs/absolute-value.tsx (new file) — Implements renderAbsoluteValueGraph, the AbsoluteValueGraph component, and two exported helpers: - getAbsoluteValueCoefficients(coords) — extracts {m, h, v} from the two control points, returning undefined if both share the same x. Uses a coeffRef to cache the last valid result for transient mid-drag states. - getAbsoluteValueKeyboardConstraint(coords, snapStep, pointIndex) — keyboard movement constraint that skips any position where the moved point would share an x-coordinate with the other point. - Renders a single <Plot.OfX y={(x) => m * Math.abs(x - h) + v} /> and two <MovablePoint> components with appropriate aria labels and an <SRDescInSVG> description. - graphs/absolute-value.test.tsx (new file) — Unit tests covering coefficient extraction (upward/downward V, varying slopes, same-x returns undefined, left/right arm equivalence), keyboard constraint skip behaviour, and all screen reader strings (graph label, point labels, description, interactive elements text). - strings.ts — Adds five new screen reader strings (srAbsoluteValueGraph, srAbsoluteValueVertexPoint, srAbsoluteValueSecondPoint, srAbsoluteValueDescription, srAbsoluteValueInteractiveElements) with i18n context comments, English defaults, and mockStrings implementations. - mafs-graph.tsx — Replaces the PR 1 throw stub with renderAbsoluteValueGraph. - interactive-graph.tsx — Implements getAbsoluteValueEquationString (returns y = m.toFixed(3)|x - h.toFixed(3)| + v.toFixed(3)) and wires it into getEquationString. - types.ts — Exports AbsoluteValueGraphState (previously unexported), required by the new component file. Author: handeyeco Reviewers: claude[bot], handeyeco, ivyolamit, SonicScrewdriver Required Reviewers: Approved By: ivyolamit Checks: ✅ 10 checks were successful, ⏭️ 1 check has been skipped Pull Request URL: #3350
Co-authored-by: Ivy Olamit <ivy@khanacademy.org>
Co-authored-by: Ivy Olamit <ivy@khanacademy.org>
0b6dc63 to
2c8e427
Compare
Everything is AI ## Summary: This is part of a series of PRs as defined in the first PR: - [Perseus#3346: PR implementation guide](#3346) - [Perseus#3348: PR1 - type definitions and schema](#3348) - [Perseus#3349: PR2 - state management](#3349) - [Perseus#3350: PR3 - rendering & accessibility](#3350) - [Perseus#3351: PR4 - scoring](#3351) -▶️ [Perseus#3352: PR5 - editor support](#3352) - [Perseus#3380: Convert todo into a long-term doc](#3380) Initial implementation experiment is [Perseus#3304](#3304). Issue: LEMS-3347 --- Add editor support for absolute-value graph type Surfaces the absolute-value graph in the content creator UI. Depends on PR 1 + PR 2 (for getAbsoluteValueCoords). No new components needed — the two-point shape fits existing patterns. Changes: - initialize-graph-state.ts — Exports getAbsoluteValueCoords (previously file-private) so the editor can import it via @khanacademy/perseus. - perseus/src/index.ts — Re-exports getAbsoluteValueCoords alongside the other getXxxCoords helpers. - graph-type-selector.tsx — Adds <OptionItem value="absolute-value" label="Absolute value" /> to the answer type dropdown. - start-coords/types.ts — Adds {type: "absolute-value"} to GraphTypesThatHaveStartCoords so the StartCoords type includes its startCoords field. - start-coords-settings.tsx — Adds case "absolute-value" using getAbsoluteValueCoords + StartCoordsPoint (the two-point shape maps directly onto the existing generic point coordinate UI). - start-coords/util.ts — Adds case "absolute-value" in getDefaultGraphStartCoords so the "Use default start coordinates" reset button returns the correct defaults. Author: handeyeco Reviewers: claude[bot], ivyolamit, handeyeco, SonicScrewdriver Required Reviewers: Approved By: ivyolamit Checks: ⏭️ 1 check has been skipped, ✅ 10 checks were successful Pull Request URL: #3352
Everything is AI ## Summary: This is part of a series of PRs as defined in the first PR: - [Perseus#3346: PR implementation guide](#3346) - [Perseus#3348: PR1 - type definitions and schema](#3348) - [Perseus#3349: PR2 - state management](#3349) - [Perseus#3350: PR3 - rendering & accessibility](#3350) - [Perseus#3351: PR4 - scoring](#3351) - [Perseus#3352: PR5 - editor support](#3352) -▶️ [Perseus#3380: Convert todo into a long-term doc](#3380) Initial implementation experiment is [Perseus#3304](#3304). Issue: LEMS-3347 Author: handeyeco Reviewers: claude[bot], ivyolamit, SonicScrewdriver Required Reviewers: Approved By: SonicScrewdriver Checks: ✅ 10 checks were successful, ⏭️ 1 check has been skipped Pull Request URL: #3380
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @khanacademy/perseus-editor@30.0.0 ### Major Changes - [#3332](#3332) [`604b3a6c25`](604b3a6) Thanks [@benchristel](https://github.com/benchristel)! - The `options` parameter of the `serialize` method of `EditorPage` and `Editor` has been removed. - [#3386](#3386) [`7e76fbbc2f`](7e76fbb) Thanks [@benchristel](https://github.com/benchristel)! - The `serialize` methods of classes in `@khanacademy/perseus-editor` no longer use arrow function syntax. Callers should not unbind them from the class instance. Additionally, the `Editor` component no longer accepts a `replace` prop (used for hints), and its serialize method no longer returns `replace`. The `replace` prop was only used in `serialize`. Users of the `Editor` component should manage hints' `replace` setting themselves. ### Minor Changes - [#3395](#3395) [`97223334ea`](9722333) Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! - Implementation of Editor support for Exponential Graph - [#3352](#3352) [`b681e00a4f`](b681e00) Thanks [@handeyeco](https://github.com/handeyeco)! - Add editor support for AbsoluteValue - [#3348](#3348) [`b1557c2a73`](b1557c2) Thanks [@handeyeco](https://github.com/handeyeco)! - Add schema for AbsoluteValue graph - [#3345](#3345) [`dde985f3b5`](dde985f) Thanks [@ivyolamit](https://github.com/ivyolamit)! - Add tangent type definitions, this is the initial implementation for supporting Tangent graph in Interactive Graph - [#3358](#3358) [`8c503171b1`](8c50317) Thanks [@ivyolamit](https://github.com/ivyolamit)! - Add tangent graph option in the Interactive Graph Editor - [#3376](#3376) [`8aa0a77886`](8aa0a77) Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! - Creation of new Types, Schema, and Kmath utilities for Exponential Graph ### Patch Changes - [#3396](#3396) [`35fa9133db`](35fa913) Thanks [@nishasy](https://github.com/nishasy)! - [Image] | (CX) | Add a linter warning for images with no size - [#3390](#3390) [`d22c50dc2a`](d22c50d) Thanks [@nishasy](https://github.com/nishasy)! - [Image] | (CX) | Make the 125 character alt text warning less aggressive - [#3372](#3372) [`3cdb09813d`](3cdb098) Thanks [@nishasy](https://github.com/nishasy)! - [Image] | (UX) | Upscale Graphies within Explore Image Modal - [#3391](#3391) [`2f285ee161`](2f285ee) Thanks [@nishasy](https://github.com/nishasy)! - [Image] | (CX) | Add character counter to alt text field - [#3374](#3374) [`cd73c99ba3`](cd73c99) Thanks [@ivyolamit](https://github.com/ivyolamit)! - Remove incorrect usage of the feature flag setting in one of the test - Updated dependencies \[[`f18c0d9b6f`](f18c0d9), [`a022e751d6`](a022e75), [`35fa9133db`](35fa913), [`54db3fd4bd`](54db3fd), [`97223334ea`](9722333), [`027a5edbda`](027a5ed), [`ae0538d0a7`](ae0538d), [`005e13d784`](005e13d), [`3cdb09813d`](3cdb098), [`afcff9f96f`](afcff9f), [`75f184e5a7`](75f184e), [`4b2a7c85db`](4b2a7c8), [`5e1acd01f8`](5e1acd0), [`b681e00a4f`](b681e00), [`d99f1c0259`](d99f1c0), [`54eee35d65`](54eee35), [`b1557c2a73`](b1557c2), [`dde985f3b5`](dde985f), [`56e7dbe9a2`](56e7dbe), [`85f9cd46fc`](85f9cd4), [`8c503171b1`](8c50317), [`3aca3dcdf4`](3aca3dc), [`9f29bc7161`](9f29bc7), [`7034844845`](7034844), [`8aa0a77886`](8aa0a77), [`003aca7612`](003aca7)]: - @khanacademy/perseus-linter@4.9.0 - @khanacademy/perseus-score@8.4.0 - @khanacademy/perseus-core@23.7.0 - @khanacademy/perseus@76.1.0 - @khanacademy/kmath@2.3.0 - @khanacademy/keypad-context@3.2.40 - @khanacademy/math-input@26.4.10 ## @khanacademy/kmath@2.3.0 ### Minor Changes - [#3351](#3351) [`005e13d784`](005e13d) Thanks [@handeyeco](https://github.com/handeyeco)! - Add scoring for AbsoluteValue - [#3347](#3347) [`d99f1c0259`](d99f1c0) Thanks [@ivyolamit](https://github.com/ivyolamit)! - Add the tangent math utilities to kmath for supporting Tangent graph in Interactive Graph - [#3376](#3376) [`8aa0a77886`](8aa0a77) Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! - Creation of new Types, Schema, and Kmath utilities for Exponential Graph ### Patch Changes - Updated dependencies \[[`54db3fd4bd`](54db3fd), [`ae0538d0a7`](ae0538d), [`005e13d784`](005e13d), [`b1557c2a73`](b1557c2), [`dde985f3b5`](dde985f), [`8aa0a77886`](8aa0a77)]: - @khanacademy/perseus-core@23.7.0 ## @khanacademy/perseus@76.1.0 ### Minor Changes - [#3350](#3350) [`75f184e5a7`](75f184e) Thanks [@handeyeco](https://github.com/handeyeco)! - Implement AbsoluteValue rendering - [#3354](#3354) [`4b2a7c85db`](4b2a7c8) Thanks [@ivyolamit](https://github.com/ivyolamit)! - Created the tangent graph visual component, add Storybook coverage, SR strings, and equation string for supporting Tangent graph in Interactive Graph - [#3353](#3353) [`5e1acd01f8`](5e1acd0) Thanks [@ivyolamit](https://github.com/ivyolamit)! - Add tangent graph state management and reducer for supporting Tangent graph in Interactive Graph - [#3352](#3352) [`b681e00a4f`](b681e00) Thanks [@handeyeco](https://github.com/handeyeco)! - Add editor support for AbsoluteValue - [#3348](#3348) [`b1557c2a73`](b1557c2) Thanks [@handeyeco](https://github.com/handeyeco)! - Add schema for AbsoluteValue graph - [#3345](#3345) [`dde985f3b5`](dde985f) Thanks [@ivyolamit](https://github.com/ivyolamit)! - Add tangent type definitions, this is the initial implementation for supporting Tangent graph in Interactive Graph - [#3349](#3349) [`56e7dbe9a2`](56e7dbe) Thanks [@handeyeco](https://github.com/handeyeco)! - Add state management for AbsoluteValue - [#3377](#3377) [`85f9cd46fc`](85f9cd4) Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! - Implementation of state management logic for new Exponential graph - [#3358](#3358) [`8c503171b1`](8c50317) Thanks [@ivyolamit](https://github.com/ivyolamit)! - Add tangent graph option in the Interactive Graph Editor - [#3393](#3393) [`9f29bc7161`](9f29bc7) Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! - Rendering logic for new Exponential Graph - [#3376](#3376) [`8aa0a77886`](8aa0a77) Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! - Creation of new Types, Schema, and Kmath utilities for Exponential Graph ### Patch Changes - [#3329](#3329) [`027a5edbda`](027a5ed) Thanks [@Myranae](https://github.com/Myranae)! - Fix image bug by batching setState calls in setupGraphie - [#3372](#3372) [`3cdb09813d`](3cdb098) Thanks [@nishasy](https://github.com/nishasy)! - [Image] | (UX) | Upscale Graphies within Explore Image Modal - [#3365](#3365) [`afcff9f96f`](afcff9f) Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Improve ordering of Props type for `Renderer` component - [#3367](#3367) [`54eee35d65`](54eee35) Thanks [@nishasy](https://github.com/nishasy)! - [Image] | (UX) | Show image in explore modal even when size is undefined - [#3407](#3407) [`3aca3dcdf4`](3aca3dc) Thanks [@Myranae](https://github.com/Myranae)! - Improve a11y with graded group set - [#3385](#3385) [`003aca7612`](003aca7) Thanks [@Myranae](https://github.com/Myranae)! - Small fix to prevent pip duplication in Graded Group Sets - Updated dependencies \[[`f18c0d9b6f`](f18c0d9), [`a022e751d6`](a022e75), [`35fa9133db`](35fa913), [`54db3fd4bd`](54db3fd), [`97223334ea`](9722333), [`ae0538d0a7`](ae0538d), [`005e13d784`](005e13d), [`d99f1c0259`](d99f1c0), [`b1557c2a73`](b1557c2), [`dde985f3b5`](dde985f), [`7034844845`](7034844), [`8aa0a77886`](8aa0a77)]: - @khanacademy/perseus-linter@4.9.0 - @khanacademy/perseus-score@8.4.0 - @khanacademy/perseus-core@23.7.0 - @khanacademy/kmath@2.3.0 - @khanacademy/keypad-context@3.2.40 - @khanacademy/math-input@26.4.10 ## @khanacademy/perseus-core@23.7.0 ### Minor Changes - [#3405](#3405) [`54db3fd4bd`](54db3fd) Thanks [@benchristel](https://github.com/benchristel)! - `@khanacademy/perseus-core` now exports a `removeOrphanedWidgetsFromPerseusItem` function, which removes unreferenced widgets from a `PerseusItem`'s question and hints. - [#3351](#3351) [`005e13d784`](005e13d) Thanks [@handeyeco](https://github.com/handeyeco)! - Add scoring for AbsoluteValue - [#3348](#3348) [`b1557c2a73`](b1557c2) Thanks [@handeyeco](https://github.com/handeyeco)! - Add schema for AbsoluteValue graph - [#3345](#3345) [`dde985f3b5`](dde985f) Thanks [@ivyolamit](https://github.com/ivyolamit)! - Add tangent type definitions, this is the initial implementation for supporting Tangent graph in Interactive Graph - [#3376](#3376) [`8aa0a77886`](8aa0a77) Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! - Creation of new Types, Schema, and Kmath utilities for Exponential Graph ### Patch Changes - [#3357](#3357) [`ae0538d0a7`](ae0538d) Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Improve code documentation for all data-schema and user-input types ## @khanacademy/perseus-linter@4.9.0 ### Minor Changes - [#3381](#3381) [`f18c0d9b6f`](f18c0d9) Thanks [@anakaren-rojas](https://github.com/anakaren-rojas)! - Adds new linters for parsed objects - [#3395](#3395) [`97223334ea`](9722333) Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! - Implementation of Editor support for Exponential Graph ### Patch Changes - [#3396](#3396) [`35fa9133db`](35fa913) Thanks [@nishasy](https://github.com/nishasy)! - [Image] | (CX) | Add a linter warning for images with no size - Updated dependencies \[[`54db3fd4bd`](54db3fd), [`ae0538d0a7`](ae0538d), [`005e13d784`](005e13d), [`d99f1c0259`](d99f1c0), [`b1557c2a73`](b1557c2), [`dde985f3b5`](dde985f), [`8aa0a77886`](8aa0a77)]: - @khanacademy/perseus-core@23.7.0 - @khanacademy/kmath@2.3.0 ## @khanacademy/perseus-score@8.4.0 ### Minor Changes - [#3356](#3356) [`a022e751d6`](a022e75) Thanks [@ivyolamit](https://github.com/ivyolamit)! - Add tangent graph scoring to support the Tangent graph in Interactive Graph - [#3351](#3351) [`005e13d784`](005e13d) Thanks [@handeyeco](https://github.com/handeyeco)! - Add scoring for AbsoluteValue - [#3394](#3394) [`7034844845`](7034844) Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! - Implementation of new scoring logic for Exponential Graph ### Patch Changes - Updated dependencies \[[`54db3fd4bd`](54db3fd), [`ae0538d0a7`](ae0538d), [`005e13d784`](005e13d), [`d99f1c0259`](d99f1c0), [`b1557c2a73`](b1557c2), [`dde985f3b5`](dde985f), [`8aa0a77886`](8aa0a77)]: - @khanacademy/perseus-core@23.7.0 - @khanacademy/kmath@2.3.0 ## @khanacademy/keypad-context@3.2.40 ### Patch Changes - Updated dependencies \[[`54db3fd4bd`](54db3fd), [`ae0538d0a7`](ae0538d), [`005e13d784`](005e13d), [`b1557c2a73`](b1557c2), [`dde985f3b5`](dde985f), [`8aa0a77886`](8aa0a77)]: - @khanacademy/perseus-core@23.7.0 ## @khanacademy/math-input@26.4.10 ### Patch Changes - Updated dependencies \[[`54db3fd4bd`](54db3fd), [`ae0538d0a7`](ae0538d), [`005e13d784`](005e13d), [`b1557c2a73`](b1557c2), [`dde985f3b5`](dde985f), [`8aa0a77886`](8aa0a77)]: - @khanacademy/perseus-core@23.7.0 - @khanacademy/keypad-context@3.2.40
Everything is AI ## Summary: This is part of a series of PRs as defined in the first PR: -▶️ [Perseus#3346: PR implementation guide](#3346) - [Perseus#3348: PR1 - type definitions and schema](#3348) - [Perseus#3349: PR2 - state management](#3349) - [Perseus#3350: PR3 - rendering & accessibility](#3350) - [Perseus#3351: PR4 - scoring](#3351) - [Perseus#3352: PR5 - editor support](#3352) - [Perseus#3380: Convert todo into a long-term doc](#3380) Initial implementation experiment is [Perseus#3304](#3304). Issue: LEMS-3347 Author: handeyeco Reviewers: claude[bot], handeyeco, ivyolamit, SonicScrewdriver Required Reviewers: Approved By: ivyolamit Checks: ⏭️ 1 check has been skipped, ✅ 10 checks were successful Pull Request URL: #3346
Everything is AI ## Summary: This is part of a series of PRs as defined in the first PR: - [Perseus#3346: PR implementation guide](#3346) -▶️ [Perseus#3348: PR1 - type definitions and schema](#3348) - [Perseus#3349: PR2 - state management](#3349) - [Perseus#3350: PR3 - rendering & accessibility](#3350) - [Perseus#3351: PR4 - scoring](#3351) - [Perseus#3352: PR5 - editor support](#3352) - [Perseus#3380: Convert todo into a long-term doc](#3380) Initial implementation experiment is [Perseus#3304](#3304). Issue: LEMS-3347 --- Add type definitions and schema for absolute-value graph type Adds the foundational type scaffolding needed to support an absolute-value graph in the Interactive Graph widget. This is a pure additive change — no runtime behavior is altered and all existing tests continue to pass. Changes: - data-schema.ts — Adds PerseusGraphTypeAbsoluteValue (type: "absolute-value", coords, startCoords) and includes it in the PerseusGraphType union. - interactive-graph-widget.ts — Registers parsePerseusGraphTypeAbsoluteValue with parsePerseusGraphType so the new type round-trips through the parser. - types.ts — Adds AbsoluteValueGraphState (mirrors SinusoidGraphState: vertex + arm point) and adds it to the InteractiveGraphState union. - interactive-graph-ai-utils.ts — Adds AbsoluteValueGraphOptions and AbsoluteValueUserInput types and wires them into getGraphOptionsForProps / getUserInput to satisfy exhaustiveness checks. - Stubs out "absolute-value" cases with throw new Error("Not implemented") in initializeGraphState, mafsStateToInteractiveGraph, renderGraphElements, and getEquationString to keep TypeScript exhaustiveness errors clear until subsequent PRs fill in the implementation. - Adds "absolute-value" to the mergeGraphs switch and shouldShowStartCoordsUI in the editor to satisfy exhaustiveness checks there as well. Author: handeyeco Reviewers: claude[bot], handeyeco, ivyolamit, SonicScrewdriver Required Reviewers: Approved By: ivyolamit Checks: ✅ 10 checks were successful, ⏭️ 1 check has been skipped Pull Request URL: #3348
Everything is AI ## Summary: This is part of a series of PRs as defined in the first PR: - [Perseus#3346: PR implementation guide](#3346) - [Perseus#3348: PR1 - type definitions and schema](#3348) -▶️ [Perseus#3349: PR2 - state management](#3349) - [Perseus#3350: PR3 - rendering & accessibility](#3350) - [Perseus#3351: PR4 - scoring](#3351) - [Perseus#3352: PR5 - editor support](#3352) - [Perseus#3380: Convert todo into a long-term doc](#3380) Initial implementation experiment is [Perseus#3304](#3304). Issue: LEMS-3347 --- Implements the full state pipeline for the absolute-value graph: initialization, reducer transitions, serialization, and test infrastructure. Depends on PR 1. No rendering yet — the renderGraphElements stub from PR 1 remains in place. Changes: - initialize-graph-state.ts — Replaces the PR 1 stub with a real initializeGraphState case. Adds getAbsoluteValueCoords(graph, range, step): returns graph.coords if set, then graph.startCoords, then normalized defaults [[0.5, 0.5], [0.75, 0.75]] (same pattern as sinusoid/quadratic). Note: currently unexported — PR 5 exports it for editor use. - interactive-graph-action.ts — Adds actions.absoluteValue.movePoint by reusing the shared movePoint action factory (same approach as sinusoid). - interactive-graph-reducer.ts — Adds a case "absolute-value" in doMovePoint that snaps/bounds the destination, then rejects the move if the two points would share the same x-coordinate (slope would be undefined). - interactive-graph-state.ts — Adds a branch in getGradableGraph() that serializes AbsoluteValueGraphState back to PerseusGraphTypeAbsoluteValue for scoring. - mafs-state-to-interactive-graph.ts — Replaces the PR 1 stub with a real case that maps state coords back to the graph type for live interaction (e.g. equation display). - interactive-graph-question-builder.ts — Adds withAbsoluteValue(options?) builder method and AbsoluteValueGraphConfig class so test fixtures can construct absolute-value questions. Author: handeyeco Reviewers: claude[bot], ivyolamit, SonicScrewdriver Required Reviewers: Approved By: ivyolamit Checks: ⏭️ 1 check has been skipped, ✅ 10 checks were successful Pull Request URL: #3349
Everything is AI ## Summary: This is part of a series of PRs as defined in the first PR: - [Perseus#3346: PR implementation guide](#3346) - [Perseus#3348: PR1 - type definitions and schema](#3348) - [Perseus#3349: PR2 - state management](#3349) -▶️ [Perseus#3350: PR3 - rendering & accessibility](#3350) - [Perseus#3351: PR4 - scoring](#3351) - [Perseus#3352: PR5 - editor support](#3352) - [Perseus#3380: Convert todo into a long-term doc](#3380) Initial implementation experiment is [Perseus#3304](#3304). Issue: LEMS-3347 --- Implement rendering and accessibility for absolute-value graph type Adds the visual component, screen reader strings, equation display, and unit tests for the absolute-value graph. Depends on PR 1 + PR 2. After this PR the graph is fully interactive and renderable. Changes: - graphs/absolute-value.tsx (new file) — Implements renderAbsoluteValueGraph, the AbsoluteValueGraph component, and two exported helpers: - getAbsoluteValueCoefficients(coords) — extracts {m, h, v} from the two control points, returning undefined if both share the same x. Uses a coeffRef to cache the last valid result for transient mid-drag states. - getAbsoluteValueKeyboardConstraint(coords, snapStep, pointIndex) — keyboard movement constraint that skips any position where the moved point would share an x-coordinate with the other point. - Renders a single <Plot.OfX y={(x) => m * Math.abs(x - h) + v} /> and two <MovablePoint> components with appropriate aria labels and an <SRDescInSVG> description. - graphs/absolute-value.test.tsx (new file) — Unit tests covering coefficient extraction (upward/downward V, varying slopes, same-x returns undefined, left/right arm equivalence), keyboard constraint skip behaviour, and all screen reader strings (graph label, point labels, description, interactive elements text). - strings.ts — Adds five new screen reader strings (srAbsoluteValueGraph, srAbsoluteValueVertexPoint, srAbsoluteValueSecondPoint, srAbsoluteValueDescription, srAbsoluteValueInteractiveElements) with i18n context comments, English defaults, and mockStrings implementations. - mafs-graph.tsx — Replaces the PR 1 throw stub with renderAbsoluteValueGraph. - interactive-graph.tsx — Implements getAbsoluteValueEquationString (returns y = m.toFixed(3)|x - h.toFixed(3)| + v.toFixed(3)) and wires it into getEquationString. - types.ts — Exports AbsoluteValueGraphState (previously unexported), required by the new component file. Author: handeyeco Reviewers: claude[bot], handeyeco, ivyolamit, SonicScrewdriver Required Reviewers: Approved By: ivyolamit Checks: ✅ 10 checks were successful, ⏭️ 1 check has been skipped Pull Request URL: #3350
Everything is AI ## Summary: This is part of a series of PRs as defined in the first PR: - [Perseus#3346: PR implementation guide](#3346) - [Perseus#3348: PR1 - type definitions and schema](#3348) - [Perseus#3349: PR2 - state management](#3349) - [Perseus#3350: PR3 - rendering & accessibility](#3350) -▶️ [Perseus#3351: PR4 - scoring](#3351) - [Perseus#3352: PR5 - editor support](#3352) - [Perseus#3380: Convert todo into a long-term doc](#3380) Initial implementation experiment is [Perseus#3304](#3304). Issue: LEMS-3347 --- Add scoring for absolute-value graph type Implements scoring for the absolute-value graph, isolated from rendering. Depends on PR 1 for the type definitions. Can be developed in parallel with PR 3. Changes: - kmath/src/coefficients.ts — Adds getAbsoluteValueCoefficients(coords), a canonical coefficient extractor returning [m, h, v] as an AbsoluteValueCoefficient tuple (or undefined if the two points share the same x). Lives in kmath alongside getSinusoidCoefficients and getQuadraticCoefficients for reuse by the scorer without taking a dependency on the rendering package. - kmath/src/index.ts — Exports the new AbsoluteValueCoefficient type. - data-schema.ts — Adds AbsoluteValueGraphCorrect (type: "absolute-value", coords: [Coord, Coord]) and includes it in the PerseusGraphCorrectType union, which is required for the rubric type to accept absolute-value correct answers. - score-interactive-graph.ts — Adds an else if branch for "absolute-value": extracts [m, h, v] coefficients from both the user input and rubric coords, then uses approximateDeepEqual to compare them. No canonical normalization is needed — the vertex uniquely defines position and m uniquely defines shape and orientation. - score-interactive-graph.test.ts — Six tests covering: undefined guess (invalid), missing coords (invalid), wrong slope (incorrect), correct answer, symmetry (p2 on either arm of the same V scores correctly), and downward-opening vs upward-opening mismatch (incorrect). Author: handeyeco Reviewers: claude[bot], ivyolamit, handeyeco, SonicScrewdriver Required Reviewers: Approved By: ivyolamit Checks: ⏭️ 1 check has been skipped, ✅ 10 checks were successful Pull Request URL: #3351
Everything is AI ## Summary: This is part of a series of PRs as defined in the first PR: - [Perseus#3346: PR implementation guide](#3346) - [Perseus#3348: PR1 - type definitions and schema](#3348) - [Perseus#3349: PR2 - state management](#3349) - [Perseus#3350: PR3 - rendering & accessibility](#3350) - [Perseus#3351: PR4 - scoring](#3351) -▶️ [Perseus#3352: PR5 - editor support](#3352) - [Perseus#3380: Convert todo into a long-term doc](#3380) Initial implementation experiment is [Perseus#3304](#3304). Issue: LEMS-3347 --- Add editor support for absolute-value graph type Surfaces the absolute-value graph in the content creator UI. Depends on PR 1 + PR 2 (for getAbsoluteValueCoords). No new components needed — the two-point shape fits existing patterns. Changes: - initialize-graph-state.ts — Exports getAbsoluteValueCoords (previously file-private) so the editor can import it via @khanacademy/perseus. - perseus/src/index.ts — Re-exports getAbsoluteValueCoords alongside the other getXxxCoords helpers. - graph-type-selector.tsx — Adds <OptionItem value="absolute-value" label="Absolute value" /> to the answer type dropdown. - start-coords/types.ts — Adds {type: "absolute-value"} to GraphTypesThatHaveStartCoords so the StartCoords type includes its startCoords field. - start-coords-settings.tsx — Adds case "absolute-value" using getAbsoluteValueCoords + StartCoordsPoint (the two-point shape maps directly onto the existing generic point coordinate UI). - start-coords/util.ts — Adds case "absolute-value" in getDefaultGraphStartCoords so the "Use default start coordinates" reset button returns the correct defaults. Author: handeyeco Reviewers: claude[bot], ivyolamit, handeyeco, SonicScrewdriver Required Reviewers: Approved By: ivyolamit Checks: ⏭️ 1 check has been skipped, ✅ 10 checks were successful Pull Request URL: #3352
Everything is AI ## Summary: This is part of a series of PRs as defined in the first PR: - [Perseus#3346: PR implementation guide](#3346) - [Perseus#3348: PR1 - type definitions and schema](#3348) - [Perseus#3349: PR2 - state management](#3349) - [Perseus#3350: PR3 - rendering & accessibility](#3350) - [Perseus#3351: PR4 - scoring](#3351) - [Perseus#3352: PR5 - editor support](#3352) -▶️ [Perseus#3380: Convert todo into a long-term doc](#3380) Initial implementation experiment is [Perseus#3304](#3304). Issue: LEMS-3347 Author: handeyeco Reviewers: claude[bot], ivyolamit, SonicScrewdriver Required Reviewers: Approved By: SonicScrewdriver Checks: ✅ 10 checks were successful, ⏭️ 1 check has been skipped Pull Request URL: #3380
Everything is AI
Summary:
This is part of a series of PRs as defined in the first PR:
Initial implementation experiment is Perseus#3304.
Issue: LEMS-3347
Add scoring for absolute-value graph type
Implements scoring for the absolute-value graph, isolated from rendering.
Depends on PR 1 for the type definitions. Can be developed in parallel with
PR 3.
Changes:
canonical coefficient extractor returning [m, h, v] as an
AbsoluteValueCoefficient tuple (or undefined if the two points share the
same x). Lives in kmath alongside getSinusoidCoefficients and
getQuadraticCoefficients for reuse by the scorer without taking a
dependency on the rendering package.
coords: [Coord, Coord]) and includes it in the PerseusGraphCorrectType
union, which is required for the rubric type to accept absolute-value
correct answers.
extracts [m, h, v] coefficients from both the user input and rubric
coords, then uses approximateDeepEqual to compare them. No canonical
normalization is needed — the vertex uniquely defines position and m
uniquely defines shape and orientation.
(invalid), missing coords (invalid), wrong slope (incorrect), correct
answer, symmetry (p2 on either arm of the same V scores correctly), and
downward-opening vs upward-opening mismatch (incorrect).