Skip to content

Adaptive Reinforcement-Based Personalized Worksheet Generation - #92

Open
vanshikaagrawalcsaiml24 wants to merge 142 commits into
vicharanashala:mainfrom
vanshikaagrawalcsaiml24:main
Open

Adaptive Reinforcement-Based Personalized Worksheet Generation#92
vanshikaagrawalcsaiml24 wants to merge 142 commits into
vicharanashala:mainfrom
vanshikaagrawalcsaiml24:main

Conversation

@vanshikaagrawalcsaiml24

Copy link
Copy Markdown

Research-Informed Adaptive Reinforcement Framework for FLN | AI-powered personalized worksheet generation based on concept-level performance, adaptive reinforcement, mastery tracking, teacher intervention, and evidence-based learning principles including Spaced Repetition and Retrieval Practice.

JINAL GUPTA and others added 30 commits July 22, 2026 16:19
…safe

The diagnostic-submit handler shelled out to the Python pipeline in a way
that could never succeed and was unsafe:

1. Wrong interpreter — it invoked `python`, which doesn't exist on the
   deployment (Ubuntu 24.04 ships python3, no bare `python`), so every run
   threw "python: not found" and silently fell back to Gemini.
2. Wrong directory — cwd was `<backend>/evaluation_metrics`, which does not
   exist; the pipeline lives in the sibling `ai-services/` (renamed in the
   restructure, never updated in code). So even a correct interpreter would
   fail on a missing cwd.
3. Command injection — `execSync` ran a shell string with `classNumber` and
   `student.id` interpolated in, so any crafted value would be shell-executed.

Fix:
- Introduce PYTHON_BIN (default `python3`) and AI_SERVICES_DIR (default the
  sibling ai-services/), both env-overridable.
- Point the pipeline cwd at AI_SERVICES_DIR.
- Replace both execSync shell strings with execFileSync + array args (no shell),
  so classNumber/student.id are passed literally and cannot inject.

Verified on the target host: `execFileSync('python3', ['run_pipeline.py', ...],
{cwd: ai-services})` now launches python3 inside ai-services and reaches the
script's own logic (no ENOENT for interpreter or cwd).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ipeline-exec

fix: make Python evaluation pipeline runnable (python3 + correct dir) and injection-safe
PDF generation (diagnostic papers, worksheet rendering) launched Puppeteer
with no usable Chrome: CHROME_EXECUTABLE_PATH was unset, Puppeteer's managed
Chrome was never (fully) installed, and there was no system Chrome — so
puppeteer.launch() threw at runtime and every PDF request 500'd. A plain
`npm install` also failed on the browser download.

- Add backend/src/browser.ts: a single launchBrowser() helper used by both
  paperGenerator.ts and worksheetRenderer.ts (removes the duplicated launch
  config). It honors CHROME_EXECUTABLE_PATH and, on failure, throws one clear,
  actionable error (install via `npx puppeteer browsers install chrome` /
  system libs / set the env var) instead of a raw Puppeteer stack.
- Document CHROME_EXECUTABLE_PATH and the browser-install step in .env.example.

Provisioning is environment setup (Option A): install the version-matched
Chrome with `npx puppeteer browsers install chrome` plus its system libraries.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…r-chrome-setup

fix: reliable headless-Chrome launch for PDF generation
frontend/src/utils/levelGenerator.ts was a byte-identical copy (except its
import line) of backend/src/levelGenerator.ts — ~485 lines that generate the
question sets AND their correct answers for all 59 levels.

It is now dead code: nothing in frontend/src imports it (a leftover from the
deleted in-browser mock, which used to generate questions client-side; the
frontend now gets questions from the API). Keeping it risked (a) silent drift
from the backend copy, and (b) leaking every question's answer key into the
client bundle if it were ever imported again.

Delete it, leaving backend/src/levelGenerator.ts as the single source of truth.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…up-levelgenerator

refactor: remove unused duplicate frontend levelGenerator
…ching)

Every API and asset URL in the frontend was hardcoded root-absolute
(`fetch('/api/...')`, `'/worksheets/x.html'`). At the domain root that works,
but under the /fln subpath a page at tenali.fun/fln/ calling fetch('/api/x')
resolves to tenali.fun/api/x — escaping the subpath. That's why the deploy had
to string-rewrite every built file (apply_fln_subpath.js) on each release.

- Add src/services/apiClient.ts: withBase(path) + apiFetch(path, init), keyed off
  import.meta.env.BASE_URL (Vite's base: "/" at root, "/fln/" for the subpath
  build). Trailing slash handled so there's no "//".
- Route all 62 fetch('/api...') calls through apiFetch, and the worksheet
  iframe/href asset URLs through withBase.
- Make the axios client (services/api.ts, used by coordinatorService) base-aware
  too (baseURL default withBase('/api') instead of a wrong localhost URL).
- vite.config: base = process.env.VITE_BASE_PATH || '/', so a subpath build just
  sets VITE_BASE_PATH=/fln/ — no --base flag and no built-file rewriting needed.

The same source now works at the root and under any subpath with zero patching.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…re-api-urls

fix: base-path-aware API/asset URLs (support /fln subpath without patching)
…ness tiers, and added PDF reinforcement badges
…ent, 4-question PDFs, and verification panel alignment
…top, non-repeating variants, and teacher alerts
…rksheet composition, and multi-concept support

- Score <40%: reinforce every worksheet
- Score 40-69%: reinforce every alternate worksheet
- Score >=80%: stop reinforcement
- 0 weak concepts: 5 normal questions
- 1 weak concept: 4 normal + 1 reinforcement
- 2 weak concepts: 3 normal + 2 reinforcement
- 3+ weak concepts: 2 normal + 3 reinforcement (top 3 weakest)
- Reinforcement questions are unique per worksheet and per concept
- Continue until concept reaches >=80% mastery or 3 cycles complete
- All 14 tests passing
…sheet and enforce score >= 80% mastery stop rule

- Score >= 80% (e.g. Number Operations 84%) now immediately deactivates reinforcement, marks concept ineligible (questionsToInject: 0), and stops reinforcement.
- Score <40% reinforces every worksheet; 40-79% reinforces every alternate worksheet.
- Reinforcement Verification Panel debug info is now generated atomically with getReinforcementQuestionsWithDebug, ensuring 100% synchronization between panel items and actual worksheet questions.
- All 15 unit tests passing.
…lation, deterministic seeding, and 100% panel-worksheet synchronization

- Use latest assessment score only for mastery percentage calculation (ignore old historical averages).
- Ensure 100% synchronization between Reinforcement Verification Panel and generated worksheets/PDFs.
- Enforce strict score >= 80% deactivation (mastered concepts automatically removed from active weak list).
- Implement deterministic PRNG question generation for student state.
- Update UI panel to render Inject badge only when questionsToInject > 0.
- All 11 unit tests passing cleanly.
…, atomic single-pdf debug execution, and 12 passing unit tests)
…roduce Remedial Intervention Required status

- A concept can show Needs Practice (score < 50%) or Satisfactory (score 50-79%) in the scorecard.
- Upon completing 3 reinforcement cycles without reaching 80% mastery, concept status becomes Remedial Intervention Required.
- Concepts with status Remedial Intervention Required or score >= 80% (Strong) are immediately deactivated and marked NOT eligible for further reinforcement.
- Scorecard, Reinforcement Verification Panel, Trigger Worksheet, and Generated PDFs remain 100% synchronized.
- Verified all edge cases, 12 unit tests passing, zero TypeScript errors in backend and frontend.
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.