Skip to content

Fix action filtering logic and add safety improvements#163

Open
zky001 wants to merge 10 commits intoTHU-MAIC:mainfrom
zky001:claude/code-review-bugs-dgHvY
Open

Fix action filtering logic and add safety improvements#163
zky001 wants to merge 10 commits intoTHU-MAIC:mainfrom
zky001:claude/code-review-bugs-dgHvY

Conversation

@zky001
Copy link

@zky001 zky001 commented Mar 20, 2026

Summary

This PR consolidates action filtering logic to prevent early returns and adds several safety improvements across the codebase, including timeout protection for video playback, better LaTeX escape handling in JSON parsing, and fixes for edge cases in video options and quiz grading.

Changes

  • Action Parser: Refactored action filtering to use a single result variable instead of multiple early returns, ensuring both slide-only and allowedActions filters are applied in sequence
  • JSON Repair: Improved LaTeX escape handling to preserve valid JSON escape sequences (\b, \f, \n, \r, \t, \u) while double-escaping LaTeX commands
  • Action Engine: Added 5-minute timeout for video playback to prevent indefinite hangs if video state changes are missed
  • Playback Engine:
    • Used queueMicrotask for spotlight/laser actions to prevent stack overflow from deep recursion
    • Added safety check for division by zero when calculating CJK language ratio
  • Stateless Generate: Moved ordered entry push inside the conditional to only emit when there's actual text content
  • Quiz Grade API: Added validation to ensure points is a positive finite number
  • Scene Generator: Fixed quiz options formatting to display both value and label
  • Video Providers: Simplified aspect ratio fallback logic to always use the first supported ratio
  • Parse PDF API: Fixed metadata property ordering to ensure pageCount is always set
  • Canvas Operations: Fixed logical operator precedence in group ID comparison
  • Order Element: Added boundary check to prevent moving elements beyond the top level

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • Refactoring (no functional changes)

Verification

What was verified

  • Action filtering now correctly applies both filters in sequence
  • JSON parsing preserves valid escape sequences while fixing LaTeX commands
  • Video playback has timeout protection against indefinite hangs
  • Edge cases handled: empty text chunks, division by zero, invalid aspect ratios, boundary conditions
  • Logical operators and property access corrected for accuracy

Evidence

  • CI passes (pnpm check && pnpm lint && npx tsc --noEmit)
  • Changes are defensive improvements and refactoring with no breaking changes

https://claude.ai/code/session_01JdigqQtiAvomeifvWSQbjm

claude added 6 commits March 20, 2026 11:22
1. formatQuestionsForPrompt called .join() on QuizOption objects,
   producing "[object Object]" in AI prompts instead of readable
   option text (e.g. "A. Option1, B. Option2").

2. json-repair Fix 1 regex double-escaped valid JSON escapes (\t,
   \n, \r, \b, \f) and couldn't handle strings with escaped quotes.
   Now uses a proper string-aware regex and preserves valid escapes.

3. PlaybackEngine spotlight/laser actions used synchronous recursion
   via processNext(), risking stack overflow with many consecutive
   non-speech actions. Now uses queueMicrotask() to break recursion.

https://claude.ai/code/session_01JdigqQtiAvomeifvWSQbjm
The early return in Step 6 (slide-only action filter) caused Step 7
(allowedActions whitelist) to be skipped for non-slide scenes. This
meant hallucinated actions from agents in quiz/interactive/pbl scenes
were not filtered by the role-based allowedActions whitelist.

Refactored to use a mutable result variable instead of early returns
so both filters always apply.

https://claude.ai/code/session_01JdigqQtiAvomeifvWSQbjm
1. executePlayVideo could hang forever if the video element was invalid
   or the state change was missed between playVideo() and subscribe().
   Added a 5-minute safety timeout to prevent indefinite blocking.

2. CJK language detection in browser TTS divided by chunkText.length
   without checking for empty strings, producing NaN. Now guards
   against zero-length text.

https://claude.ai/code/session_01JdigqQtiAvomeifvWSQbjm
…o remaining content

When a previously-partial text item completed but all content had
already been streamed as deltas (remaining is empty), the code still
pushed an ordered entry pointing to textChunks.length - 1, which
could be -1 or reference an unrelated chunk. This caused spurious
warnings in director-graph and potential text loss.

Now only pushes the ordered entry when there is actual remaining
content to emit.

https://claude.ai/code/session_01JdigqQtiAvomeifvWSQbjm
… order

1. quiz-grade: `points` from request body was used without validation,
   causing NaN in score calculation and invalid JSON responses when
   points was undefined, negative, or non-numeric. Now validates it
   is a positive finite number.

2. parse-pdf: metadata spread order put the default `pageCount` before
   `...result.metadata`, so the spread would overwrite the fallback.
   Fixed by spreading metadata first, then applying defaults after.
   Also changed `||` to `??` so pageCount=0 is preserved correctly.

https://claude.ai/code/session_01JdigqQtiAvomeifvWSQbjm
… in canCombine

1. use-order-element.ts: moveUpElement crashed with TypeError when a
   grouped element was already at the top of the z-order. The code
   accessed copyOfElementList[maxLevel + 1] without bounds checking,
   then dereferenced .groupId on undefined. Added early return guard
   matching the pattern used in the non-grouped branch.

2. video-providers.ts: normalizeVideoOptions had a dead-code ternary
   inside an if-block that already proved the condition was false.
   Simplified to directly use the fallback value.

3. use-canvas-operations.ts: canCombine check had incorrect
   parenthesization: (el.groupId && el.groupId) === firstGroupId
   evaluated the && first, which is equivalent to just el.groupId.
   Fixed to: el.groupId && el.groupId === firstGroupId.

https://claude.ai/code/session_01JdigqQtiAvomeifvWSQbjm
Copilot AI review requested due to automatic review settings March 20, 2026 11:28
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR strengthens several runtime safety edges in the generation/playback pipeline while also fixing a few correctness issues (action filtering, quiz option formatting, JSON repair, and ordering/grouping edge cases) to reduce hangs and malformed outputs.

Changes:

  • Consolidates action filtering so slide-only stripping and allowedActions whitelisting are applied sequentially.
  • Hardens playback and parsing: microtask scheduling for rapid spotlight/laser sequences, division-by-zero guard for language detection, safer LaTeX escaping in JSON repair, and a timeout to prevent indefinite video waits.
  • Fixes smaller correctness issues across quiz prompting, PDF metadata normalization, video option normalization, canvas grouping checks, and element ordering boundaries.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated no comments.

Show a summary per file
File Description
lib/playback/engine.ts Avoids deep synchronous recursion for consecutive effect actions and guards against division by zero in TTS language detection.
lib/orchestration/stateless-generate.ts Prevents emitting ordered text entries when no actual text delta is produced.
lib/media/video-providers.ts Simplifies aspect ratio fallback to consistently pick the provider’s first supported ratio.
lib/hooks/use-order-element.ts Adds boundary protection when moving grouped elements upward in z-order.
lib/hooks/use-canvas-operations.ts Fixes group comparison predicate for determining if selection can be grouped.
lib/generation/scene-generator.ts Formats quiz options using both option value and label in prompts.
lib/generation/json-repair.ts Preserves valid JSON escapes while double-escaping LaTeX command escapes inside strings.
lib/generation/action-parser.ts Ensures slide-only and allowedActions filters both apply in sequence without early returns.
lib/action/engine.ts Adds a safety timeout to prevent playback hangs when waiting for video completion state.
app/api/quiz-grade/route.ts Validates points as a positive finite number before grading.
app/api/parse-pdf/route.ts Ensures pageCount is always set and not overwritten by metadata spread ordering.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@zky001
Copy link
Author

zky001 commented Mar 21, 2026

@wyuc @YizukiAme fixing a few correctness issues (action filtering, quiz option formatting, JSON repair, and ordering/grouping edge cases) to reduce hangs and malformed outputs.

@YizukiAme
Copy link
Contributor

YizukiAme commented Mar 21, 2026

@wyuc @YizukiAme fixing a few correctness issues (action filtering, quiz option formatting, JSON repair, and ordering/grouping edge cases) to reduce hangs and malformed outputs.

Hey dude, I think you might have @'d me thinking I'm a maintainer...? I'm actually just a random community contributor 🙃
That said, I did take a quick look at your changes and most of them LGTM~!
Personally, one minor concern though: in json-repair.ts, LaTeX commands like \frac could have their first letter f mistakenly treated as the valid JSON escape \f, which might need a few more test cases to cover those edge cases~

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.

4 participants