S171
Lexi ITS · Exam Sim · Error Taxonomy · Parent Dashboard
2026-04-19
CURRENT
ITS Interface Model completed (Lexi): Persistent companion widget across all 5 pages (32px quiz / 56px FAB / 84px tutor). 5 expressions via SVG path-swap. Blink animation. Quiz reactions via MutationObserver. lexi.js self-contained IIFE.
/tutor home page: Daily brief from live BKT data. SAC countdown. Session planner card (PLAN→IN_PROGRESS→DEBRIEF state machine via GET /api/tutor/session). Confidence calibration card. Today's Focus driven by weakest BKT topic.
Quiz engine additions: Confidence calibration (1–5 pre-answer, stored in quiz_attempts.confidence_before). Show Answer escape hatch (POST /api/view-answer, SM-2 reset, 2-day interval, Kapur 2016). Sub-80% score → forced 1-day interval + growth-mindset framing. Error taxonomy (misconception/forgotten/never_learned/correct) returned by scorer and stored in quiz_attempts.error_type.
Socratic hints: GET /api/hints/{id} — Claude Haiku generates 3-tier hints on first request (~2s), cached in question_hints table forever. Tier 1: concept nudge → Tier 2: key term → Tier 3: answer structure. Never reveals the answer.
Exam simulation (/exam): Topic + mark budget selector. Countdown timer (1.2 min/mark). No hints, no Show Answer, no confidence rating. Background parallel scoring (Promise.all). Results with SAC-equivalent grade A–E and per-question model answers.
Parent dashboard (/parent): GET /api/parent/summary — 7-day activity chart, topic mastery bars (learning/consolidating/mastered), error taxonomy breakdown, recent exam results. Auto-refreshes every 60s. Linked from tutor.html nav.
URL topic pre-selection: /quiz?topic=KK4 pre-filters sidebar and loads first question from that topic on boot.
Melbourne timezone: GET /api/tutor/greet time_of_day uses AEST (UTC+10) not server UTC.
Cleanup: quiz_errors.jsonl consolidated to /opt/aela/data/. /exam and /parent nginx routes added. Exam nav link in quiz.html and tutor.html.
DB changes: quiz_attempts + confidence_before, viewed_answer, exam_mode, error_type. New question_hints table.
Files changed: aela_quiz_server.py, aela_sac2_agent.py, web/quiz.html, web/tutor.html, web/exam.html (new), web/parent.html (new), web/lexi.js (new), nginx-default.conf. Commits: fe74e01, 1dc596a, 3ef4ab6.
S170
HTTPS Live · Model Routing Wired
2026-04-19
PREVIOUS
HTTPS activated: OCI VCN Security List TCP 443 ingress rule added.
https://34-142-152-26.sslip.io/ returns 200 OK. Cert (Let's Encrypt, sslip.io wildcard) valid Jul 2026. HTTP→HTTPS redirect active on port 80.
Model routing wired + hardened (aela_model_router.py):
All services route through the central router. Gemini alias strategy documented —
-latest rolling aliases used for LITE/FLASH (Google-maintained, stable);
gemini-2.5-flash pinned for FLASH25 (implicit caching requires specific generation). To update a model, change one constant in
aela_model_router.py.
Local Qwen3.5-9B wired via
local_complete() with
enable_thinking=False (required — thinking tokens otherwise consume all n-predict budget returning empty string). Benchmarked: LITE=1.5s, FLASH=2.3s, LOCAL=5s — LOCAL reserved for batch/background and API fallback.
- LITE (
gemini-flash-lite-latest, ~1.5s): drill PASS/FAIL, nudges, status, braun-tracking 2-sentence summary
- FLASH (
gemini-flash-latest, ~2.3s): 6-class error scoring, tutor remediation, Braun dialogue, examiner/challenger
- FLASH25 (
gemini-2.5-flash, ~4s): study guide synthesis — implicit prompt caching on repeated dot-point synthesis
- Claude Haiku (
claude-haiku-4-5): quiz answer scoring — structured JSON rubric, VCAA-precise marks/feedback
- Claude Sonnet (
claude-sonnet-4-6): deep mistake explanations — Mayer cognitive theory, 4-5 sentence personalised analysis
- LOCAL Qwen3.5-9B (port 8080, $0): batch tasks, /deepsolve, /deepq, API fallback via
local_complete()
Files changed: aela_model_router.py (rewrite),
aela_gateway.py,
aela_quiz_server.py,
study_guide_maker.py. 157/157 tests pass. Commits: 406a7aa, 72ac1a2.
S169
Open Issues Cleared · Pre-SAC Roadmap Complete · Braun Upgrades
2026-04-19
PREV
Open Issues (all 3 HIGH/MEDIUM resolved):
- Quiz BKT → study.html sync:
GET /api/guide-mastery maps quiz topics to SAC 2 dot-point IDs. study.html fetches this in parallel with scorer data and takes Math.max(sm2_level, bkt_level). BroadcastChannel('aela-mastery') re-fetches live after every quiz score.
- Braun memory: localStorage serialises last 60 messages on every push.
braun_sessions SQLite table + GET/POST /api/braun-history provides server-side persistence — server history wins on load if longer.
- guides.html progress bars: DOMContentLoaded JS counts real
.dp-done rows dynamically. Fix embedded in content watcher generator — survives hourly rebuilds.
Pre-SAC roadmap complete:
- SM-2 algorithm audited — correct. quiz_attempts INSERT verified via direct DB test.
- All 7 SAC 2 guides (dp3-7, 67, 68) verified viewable from gold-standard docx. dp67+68 docx copied to webroot (AI fallback replaced with full 15KB guide).
GET /api/braun-tracking + "📊 How am I tracking?" button: pulls live BKT+streak+attempt stats, calls Gemini, returns 2-sentence SAC-readiness summary.
Post-SAC roadmap progress: server-side Braun memory (SQLite), BroadcastChannel real-time mastery sync, Braun cross-portal awareness (guide context in localStorage → injected into Braun chat), 107 study guides generated (exceeds 74-guide target).
Smoke test results (S169 stable): 33/33 API checks pass. 157/157 pytest tests pass. All 10 services + 5 timers active. All 7 SAC 2 view-guide endpoints return full HTML (14–23KB). quiz_attempts INSERT verified live. SM-2 scheduling verified (no zero-interval regressions). guides.html dynamic JS confirmed in content watcher generator (survives hourly rebuilds).
S168
Vision Fallback for Unreadable PDFs · Smarter Table Quality Checking
2026-04-18
The problem this solves: AELA ingests PDFs — past exams, textbooks, study resources — and converts them to Markdown so Khoj can index and search them. Some PDFs are scanned images with no text layer. Others are exported with broken fonts. Before S168, if Docling's text extraction failed and Tesseract OCR also failed, AELA logged an error and the document was silently lost — never indexed, never searchable, never available for study guides or quiz generation. For a VCE student with limited study resources, a lost document is a real gap.
What changed — the third attempt: When both text extraction and OCR fail, AELA now has a third option. It renders each page of the PDF as a high-resolution image, slices wide or tall pages into smaller tiles so nothing gets cropped or distorted, then sends those images to Gemini with a precise structured prompt. Gemini reads the page visually — the same way a human would — and outputs clean, structured Markdown. The result is written to the knowledge base exactly like any other converted document. No document is silently lost anymore.
What the structured prompt enforces: The Gemini prompt isn't just "describe this page." It instructs the model to output math as proper LaTeX ($...$ inline, $$...$$ for equations), tables as HTML with merged cells preserved, and figures with their position on the page. This matters because a Biology diagram described as "a circle with arrows" is useless — but a properly captioned figure with spatial context is searchable and referenceable.
What changed — table quality checking: Previously, AELA checked tables by comparing row counts and loosely matching cell text. A table could pass the quality check even if columns had silently collapsed — for example, a 3-column enzyme kinetics table being converted to 2 columns, losing a whole data dimension. The upgraded checker now compares the full shape of a table: rows, columns, and content together. A column-count regression that the old scorer would miss is now caught and flagged before the document enters the knowledge base.
Why this matters for study: Khoj's answer quality is only as good as what's in the knowledge base. A failed ingest means Khoj can't answer questions from that source. A silently degraded table means Khoj gives incomplete answers about enzyme rates, genetic crosses, or experimental data — without either system knowing something is wrong. S168 closes both gaps: more documents get in, and the ones that do get in are structurally verified.
Tests: 54 new tests — 103 → 157 passing. Every new function is tested in isolation including all edge cases (empty tables, missing API key, network failures, malformed HTML, page tile counts).
S167
VaultResolver · Resolver Audit · Trigger Evals · S167 Cleanup
2026-04-18
VaultResolver (vault_resolver.py): single source of truth for where ingested content lands in the Obsidian vault. resolve(subject, content_type) → absolute vault path; resolve_auto(path) auto-detects subject and content type from filename. 17 content types mapped across Biology/Psychology/Chemistry. Subject aliases (bio/psych/chem). Inbox fallback for unknowns. Full audit trail to ingest_resolve.jsonl (gbrain ingest_log pattern).
RESOLVER.md (docs/): 4-part routing document: (1) Telegram input → agent/endpoint routing table (28 trigger patterns). (2) Vault filing rules and misfiling prevention. (3) Full service registry — FastAPI, Khoj, systemd, timers. (4) Context injection preamble for Khoj agents.
check_resolvable.py: weekly service graph audit across 5 check categories — FastAPI endpoints, Khoj KB context gate (≥100 chars), systemd active/timer/parked/oneshot, vault directory structure, deprecated file notices. Outputs to resolvable_report.jsonl. --fix-hints for remediation.
run_trigger_evals.py + trigger_evals.json: 25-item routing smoke test (critical/high/medium/low priority). Tests all quiz API endpoints, Khoj agents, gateway routing. Pass threshold: 80%. Results to trigger_eval_results.jsonl.
snapshot_resolver_hook.sh: wired into snapshot.sh — runs resolver audit + trigger evals (critical only) + vault spot-check + RESOLVER.md staleness check on every snapshot.
Wiring: study_guide_maker.py routes via VaultResolver instead of hardcoded path. aela_convert.py logs every conversion to VaultResolver audit trail. 30-test suite for vault_resolver added to CI.
S162–S166
Session Transfer System · Manifest Consolidation · Home Cleanup
2026-04-18
Session context transfer system: End-to-end Claude Code ↔ Claude.ai context sharing. Counter file at /opt/aela/data/aela_session_number.txt replaces fragile dir-scanning for session numbering. gen_manifest.py v3 generates 482-line manifest from live system state — services, DB counts, feature verification, MA gap status, model routing, learning science principles, all locked decisions, all gotchas.
Windows folder watcher: aela_watcher.ps1 (FileSystemWatcher) monitors AELA-Downloads\ on laptop. Auto-SCPs .md manifests and .zip payloads to OCI. Server-side process_upload.sh handles routing: .md → /var/www/html/snapshots/combined.md + Telegram notify; .zip → /tmp/aela_staged/ + Telegram notify. Started via Windows Startup folder shortcut (no admin required).
Manifest consolidation: 54 server manifests + 121 laptop session files absorbed. All missing context (MA gaps, model routing, ContextGuard, temporal decay, typed failures, OCR bugs) permanently embedded in gen_manifest.py. CLAUDE.md updated: first action every session is to read combined.md as ground truth.
Home root cleanup: 150+ files → 8 items. Pre-cleanup snapshot (8.1GB) at /opt/aela/data/snapshots/pre_cleanup_20260418_020252.tar.gz. All stale/temp files archived to ~/.archive/. All services verified active after cleanup.
MA Gap 23 — Spacing optimisation: Topic difficulty spacing matrix implemented in sm2_update(). Computes per-topic avg score from quiz_attempts (min 5 attempts to activate), maps to a [0.75, 1.25] interval multiplier applied on the SM-2 success path only. Hard topics → shorter intervals; easy topics → longer. Dormant until quiz sessions accumulate. MA gap count: 46/51.
PDF quality pipeline (ParseBench + LiteParse patterns): New aela_parse_quality.py module combining two open-source repos.
ParseBench patterns: BaselineRule — empty/near-empty/repetitive detection. GriTS table checker — markdown tables vs Docling native export; flags fidelity <0.75. Layout bbox sidecar — .layout.json per PDF with label/page/bbox/text for every item. LaTeX normalization — strips LaTeX + fenced code before quality checks.
LiteParse patterns: GarbledTextRule — detects PUA unicode (broken font CMap) and box-drawing chars that fool BaselineRule into thinking text was extracted cleanly. fitz pre-check — PyMuPDF counts chars per page in milliseconds before loading Docling; if sparse pages detected, skips the wasted do_ocr=False pass and goes straight to Tesseract. tesseract_page_confidence — pytesseract per-page confidence (0–1) stored in layout sidecar; pages <0.3 logged as warnings. All quality metrics in convert_decisions.jsonl.
S161+
Quiz UX Complete · Smoke Tested · Stats Reset
2026-04-17
Interactive Braun guided session: Topic chip selection (All / KK4 / KK5 / KK6 with due counts) → phase chip selection (All / Review / Learn / Strengthen) → launches filtered guided queue. braunStartGuided() fast-path bypasses selection and launches full plan immediately.
Session counter: q-session-prog chip ("3 / 12") on quiz card header during guided sessions. Hidden in free practice. Updated by nextGuidedQuestion(), cleared by renderQuestion().
Session tab enhancements: Clickable rows — click any session history row to drill that exact question. OOS flag button per row — toggles Out of Scope, dims row with red border, updates mastery.db. Topic label shown on each row.
Sidebar topic labels: Now show "X% · N due · M total q" — question count added alongside pct and due.
Stats reset: mastery.db wiped clean (quiz_attempts, quiz_question_mastery, xp_events, review_sessions, study_streak). Alea starts fresh with a clean slate from 2026-04-18.
Infrastructure fixes: dashboard.html chmod 644 (was 600, nginx couldn't read it). /guides redirect added to HTTP (port 80) server block — was only in HTTPS block.
Smoke tested: 83-check quiz app smoke test (all passing) + 52-check ecosystem smoke test across all 14 systemd services. All services active/running confirmed.
Bugs fixed: solBannerHtml undefined (masked as API error) · braunStartGuided() not calling nextGuidedQuestion() · freePractice() replacing broken "Let me choose" · braunStartGuided() cycling by re-calling braunGreet() · missing showView('quiz') in braunSelectPhase() · dashboard.html 403 · /guides 404 on HTTP.
S161
Web Portal Layer Complete
2026-04-17
The Braun: Brain-avatar orchestration agent. Welcome overlay with solo/guided mode choice. Floating FAB with animated inline SVG. Gemini Flash chat panel with mastery context injection. Guided session queue wired to /api/session-plan.
Guide viewer rebuilt: mammoth.js CDN abandoned (server has no outbound internet). Server-side python-docx conversion. Fuzzy file matching (Biology_N_* prefix). Gemini Flash AI generation for all missing guides (~10s first visit, 25ms cached).
Session plan orchestrator: /api/session-plan — 3-phase plan (review due / learn new / strengthen weak). Plan tab in quiz UI. Guided session mode with phase transition banners.
Science of Learning banner: AI-personalised per question via Gemini Flash. AbortController cancels in-flight requests on question change. Static fallback pool with study citations.
Jargon removed: BKT → Memory X%. All mastery labels plain English. Context phrases on every metric. Sidebar metrics with callout phrases.
Bugs fixed: Mastered-question looping (Prolog prereq BKT≥0.85 skip) · Gemini truncation (thinkingBudget:0 now mandatory globally) · quiz-empty persistence (renderQuestion() hides it) · modal CSS deletion · _ureq scope error · guide 404s (fuzzy match + AI gen).
Architecture document: Rebuilt as architecture.html in AELA design system (this page). Replaces the messy docx approach.
S140–S160
Quiz Engine & Platform Foundation
2026-03 → 2026-04
Built the core quiz engine: SM-2 spaced repetition, BKT Bayesian Knowledge Tracing, Prolog KB prerequisite graph, interleaving, mastery tracking. Deployed 192 Biology SAC 2 questions across KK4/KK5/KK6. guides.html with 74 study guides. Khoj agent fleet (8 agents). Prolog KB layer. OOS flagging. XP/streak/level system. Claude Haiku scoring. Session summary view. Progress dashboard.
S50–S139
Infrastructure, Agents & Knowledge Base
2025 → 2026-03
OCI instance provisioned. Discord + Telegram bots. Agent fleet architecture (LaneQueue, ContextGuard, SessionStore). Khoj knowledge base with RAG. Content pipeline for guide generation. SVG diagram system. OpenMAIC/OpenWebUI setup. Crontab automation. Backup system (Google Drive + GitHub). Cost architecture.