Skip to content

fix(learn): greptile review comments + swap arrow chars for lucide icons#43

Open
devin-ai-integration[bot] wants to merge 2 commits into
mainfrom
devin/1778869109-greptile-pr42-fixes
Open

fix(learn): greptile review comments + swap arrow chars for lucide icons#43
devin-ai-integration[bot] wants to merge 2 commits into
mainfrom
devin/1778869109-greptile-pr42-fixes

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot commented May 15, 2026

Summary

Follow-up to #42 addressing the four greptile-apps review comments left on that PR, plus a small UI polish (raw unicode arrows replaced with lucide icons after user feedback that the back-link UI looked bad).

Greptile review fixes

# Severity File Change
1 P1 public/learn-runtime/python-runner.worker.js Reset cached pyodidePromise to null when the Pyodide load rejects, so a single CDN failure (network blip, bad version path, etc.) doesn't permanently brick the Python runner for the rest of the session. Added a belt-and-suspenders second reset in the outer await as well.
2 P2 public/learn-runtime/python-runner.worker.js Stdout/stderr were being appended one character at a time with +=, which is O(n²) overall. Switched to a byte-array buffer and a single TextDecoder.decode at the end.
3 P2 components/learn/LessonWorkspace.tsx loadLanguagePref() was casting the raw localStorage value straight to LessonLanguage. A stale or tampered value (e.g. "rust") would slip through. Now validates against an ALL_LESSON_LANGUAGES-derived set before returning.
4 P2 components/learn/LessonWorkspace.tsx The runner module already exports terminateAllRunners() but it was never called. Added a useEffect cleanup so that pending jobs and the main-thread kill timer get torn down when the user navigates away mid-run.

UI polish

Swapped raw unicode arrows (, ) for lucide-react icons on the learn back/prev/next links in three places:

  • components/learn/LessonWorkspace.tsx — course back link (text-xs) + lesson prev/next pagination (text-sm)
  • components/learn/QuizWorkspace.tsx — course back link
  • app/learn/[course]/page.tsx — Learn back link

Each link is now inline-flex with a 1.5-unit gap so the icon and text share a baseline; icon size scales with the link's text size (h-3.5 w-3.5 for text-xs, h-4 w-4 for text-sm).

Review & Testing Checklist for Human

  • Open /learn/arrays-easy/01-largest-element, switch to Python, click Submit. Should still report 5/5 (regression check — same pyodide path, just different stdout collection).
  • In DevTools, set localStorage["codejeet:learn:v2:lang"] = "rust", reload the page. The language selector should fall back to the course default instead of trying to render Rust.
  • Navigate into a lesson and immediately back out before any toolchain finishes loading; no console errors about pending jobs after navigation.
  • Confirm the back-link icons render correctly on /learn/arrays-easy (Learn back), /learn/arrays-easy/01-largest-element (Arrays — Easy back + Next lesson), and /learn/arrays-easy/quiz/01-array-basics (course back).
  • CI green + Cloudflare Workers preview builds.

Notes

  • I'm not committing the regenerated lib/learn/generated.ts even though bun run prebuild produces a diff against main. The diff is purely stylistic (quoted vs unquoted JSON keys) and orthogonal to the review comments — keeping the PR focused on the actual fixes.
  • The Pyodide retry behavior is intentionally conservative: we don't auto-retry on the same submit. If the first load rejects, the current submit fails with errorKind: "internal" but the next Submit will trigger a fresh load attempt instead of re-awaiting the bad promise.
  • The useEffect(() => () => terminateAllRunners(), []) cleanup runs on unmount only (empty deps). Switching language within the same lesson does not tear down workers, which is the desired behavior — we want to keep the warmed-up Pyodide/browsercc instances around for subsequent Submits.

Link to Devin session: https://app.devin.ai/sessions/37c6cc147b4e4ff1bf85ae32a42cf61d
Requested by: @ayush-that


Open in Devin Review

- python-runner.worker.js: reset cached pyodide promise on load failure so a
  single CDN hiccup doesn't permanently brick the runner for the session (P1)
- python-runner.worker.js: collect stdout/stderr as byte arrays and decode
  with TextDecoder at the end instead of O(n^2) char-by-char string concat (P2)
- LessonWorkspace.tsx: validate the stored language preference against the
  known LessonLanguage set before returning it from localStorage (P2)
- LessonWorkspace.tsx: tear down all language workers on component unmount
  via terminateAllRunners() so pending jobs and kill timers don't leak when
  the user navigates away mid-run (P2)

Co-Authored-By: Lakkhan Madarchod <ayush1337@hotmail.com>
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 15, 2026

Greptile Summary

This PR is a focused follow-up to #42 that fixes four issues flagged in the previous review: resetting the cached Pyodide promise on CDN failure, switching stdout/stderr collection from O(n²) string concatenation to a byte-array buffer, adding a runtime guard on the localStorage language preference, and wiring up a useEffect cleanup to call terminateAllRunners on unmount.

  • python-runner.worker.js: The promise-reset logic now handles both the IIFE-inner catch and the outer await catch, ensuring a rejected Pyodide load doesn't permanently brick the runner. The byte-array approach also silently fixes a latent correctness bug where String.fromCharCode(byte) would mishandle multi-byte UTF-8 output (e.g., emoji/non-ASCII characters).
  • LessonWorkspace.tsx: The VALID_LANGUAGES guard prevents stale or manually tampered localStorage values from reaching the language selector, and the new cleanup useEffect ensures workers and their kill timers are torn down on route change.

Confidence Score: 5/5

All four changes are narrowly scoped, correctly implemented, and introduce no new side-effects.

The Pyodide promise reset is correctly placed in both the inner IIFE catch and the outer await catch; microtask scheduling in the worker's single-threaded event loop eliminates any interleaving hazard between the two resets. The byte-array switch is a straightforward correctness and performance improvement that also incidentally fixes UTF-8 multi-byte output (previously mangled by String.fromCharCode). The localStorage guard and the cleanup useEffect are small, well-isolated changes with no surprising interactions.

No files require special attention.

Important Files Changed

Filename Overview
public/learn-runtime/python-runner.worker.js Correctly resets pyodidePromise on CDN failure (both inner IIFE catch and outer await catch). Byte-array stdout/stderr collection is correct and also fixes a latent UTF-8 multi-byte decoding bug from the old String.fromCharCode approach. Race condition analysis shows the outer catch microtasks run before any new message macrotask, so no concurrent-load hazard.
components/learn/LessonWorkspace.tsx Language preference validation via VALID_LANGUAGES.has(raw) correctly guards against stale/tampered localStorage values. The cleanup useEffect with empty deps calls terminateAllRunners only on unmount, which is the right granularity. React 18 treats state updates on unmounted components as no-ops, so any in-flight handleRun/handleSubmit resolution after unmount is harmless.

Reviews (1): Last reviewed commit: "fix(learn): address greptile review comm..." | Re-trigger Greptile

Copy link
Copy Markdown
Contributor Author

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 4 additional findings.

Open in Devin Review

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 15, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
codejeet 7e76637 Commit Preview URL

Branch Preview URL
May 16 2026, 09:58 AM

…ext links

Replace unicode \u2190 / \u2192 with ArrowLeft / ArrowRight from lucide-react in:
- components/learn/LessonWorkspace.tsx (course back link + prev/next pagination)
- components/learn/QuizWorkspace.tsx (course back link)
- app/learn/[course]/page.tsx (Learn back link)

Each link now uses inline-flex with a 1.5-unit gap so icon and text sit on the
same baseline. Sizes scale with text: h-3.5/w-3.5 for text-xs, h-4/w-4 for
text-sm.

Co-Authored-By: Lakkhan Madarchod <ayush1337@hotmail.com>
@devin-ai-integration devin-ai-integration Bot changed the title fix(learn): address greptile review comments on PR #42 fix(learn): greptile review comments + swap arrow chars for lucide icons May 16, 2026
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

Devin Test Results — All 4 tests passed

Tested on branch preview: https://devin-1778869109-greptile-pr42-fixes-codejeet.shydev.workers.dev

# Test Result
1 Course landing page back link uses lucide-arrow-left SVG passed
2 Lesson page back link + prev/next pagination use lucide icons (3 SVGs verified, arrow-right on right side of next-link text) passed
3 Quiz page back link uses lucide-arrow-left SVG passed
4 localStorage guard: setting codejeet:learn:v2:lang = "rust" then reloading falls back to C++ default, page mounts cleanly passed

Heads-up (non-blocking)

ReferenceError: __name is not defined is thrown by an inline <script> on every learn page load. Looks unrelated to PR #43 — Cloudflare Workers static export quirk where esbuild's __name helper isn't bundled in the inline script. Does NOT prevent the page from rendering, but worth a follow-up.

Before vs After (most adversarial check)

Production still has the raw chars; PR #43 preview has lucide icons. Same URL path, different output.

🔴 BEFORE — production codejeet.com

DOM: <a>← Arrays — Easy</a> and <a>Second largest element →</a> (raw unicode chars)

Production: raw arrow chars

🟢 AFTER — PR #43 branch preview

DOM: <a><svg class="lucide lucide-arrow-left"…/>Arrays — Easy</a> and <a>Check if an array is sorted<svg class="lucide lucide-arrow-right"…/></a>

Preview: lucide icons

Test 4 — localStorage poison + reload

Set localStorage["codejeet:learn:v2:lang"] = "rust", reloaded. Selector falls back to "C++" (the course default), editor shows C++ starter code, no crash, no "rust" tab. The dropdown contains only C++/JavaScript/Python.

Falls back to C++ after poison + reload

Not visually tested (intentional)

The remaining greptile fixes are correct by code review and CI build but not visually distinguishable in a recording:

Greptile re-reviewed PR #43 with 5/5 confidence on these.

Devin session: https://app.devin.ai/sessions/37c6cc147b4e4ff1bf85ae32a42cf61d

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.

1 participant