ExamAdvantage — Changelog
Certification Tool and Die, Ltd. · (ISC)² and ISACA certification courses
Release 26239_01 — August 27, 2026
Course DBs · Course content update · CISM + CRISC initial delivery · All 9 (ISC)² exams rebuilt · No program changes
CISM and CRISC — Initial Course Delivery
The first two ISACA course databases are now available for download:
CISM — Certified Information Security Manager — 3,537 study leaves, 10,611 questions across 4 domains (17% / 20% / 33% / 30%).
CRISC — Certified in Risk and Information Systems Control — 1,896 study leaves, 5,688 questions across 4 domains (26% / 20% / 32% / 22%).
Both databases include the full-text search index, ISACA-specific glossary definitions via certBodyDefs, and all editorial standards described below. A deep audit was run against both corpora before release; the items below document what was found and corrected.
CISM Content Fixes
A deep audit surfaced residual editorial issues not caught by the pre-delivery audit pass:
Banned vocabulary (prose): Leaf 3B1.a.l [example] — "seamless-sounding compliance certifications" corrected to "superficially compliant-sounding certifications."
British spelling (prose): Leaf 1B1.a.a — "catalogue" corrected to "catalog" in the P1 paragraph and example block. Six additional leaves (2A.c.v, 2B3.a.q, 3B3.b.g, 3B3.b.i) contained the past-tense form "catalogued" (missed by the earlier regex which only tested \bcatalogue\b); corrected to "cataloged."
34 em-dashes in figure SVG content confirmed SVG-exempt per editorial standards; zero prose violations.
CRISC Content Fixes
Banned vocabulary (question stem): Leaf 1A3.b.b — "genuinely risk-aware" corrected to "truly risk-aware."
British spelling (prose): "catalogue" and inflected forms corrected to "catalog / catalogs / cataloged / cataloging" in 10 prose blocks across 8 leaves: 1B3.a.d, 1B5.T09.a, 3C3.b.b.d, 4B1.d.e, 4B3.a.k, 2A.T04.a, 2B2.b.a, 4A2.c.i.c. Root cause: the earlier audit regex used \bcatalogue\b and did not match inflected forms — extended to catalogue(?:d|s|ing)?.
Glossary Integrity Pass
All nine (ISC)² course databases rebuilt following a multi-round glossary cleanup. Changes in this pass:
Removed 96 ALL-CAPS acronym-first entries (e.g., VPN (VIRTUAL PRIVATE NETWORK), LAN (LOCAL AREA NETWORK)) that were holdovers from an earlier import format. Replaced with 70 canonical sentence-case forms (e.g., Voice-over-internet protocol (VoIP), Local area network (LAN)).
Resolved a VPN duplicate: two separate entries previously referred to the same concept. One canonical entry now covers the term.
Net glossary size: 3,079 → 3,058 authoritative entries (52 CIS Controls task stubs with no definition text are excluded from the compiled database; 3,006 entries are inserted per DB).
Confirmed that certBodyDefs overrides for Audit, Governance, Incident, and Risk resolve to the (ISC)²-specific definitions in all nine databases.
ISACA Glossary Expansion
The shared glossary was expanded and restructured to serve both (ISC)² and ISACA exam databases from a single source.
Format migration: glossary_master.json migrated from a flat {term: defn} dict to a list-of-objects format [{term, acronym, defn, url, certBodyDefs}] with a metadata block (schema version, content version, entry count, SHA-256 checksum, timestamp, author).
ISACA-specific terms: 454 new terms sourced from five ISACA reference works (CISM Review Manual 15th/16th editions, CRISC Review Manual 8th edition, CISM All-in-One 2nd edition, CRISC All-in-One 2nd edition) and vetted for OCR quality, minimum word count, and exact-match deduplication against existing entries. Terms where a single definition applies to both cert bodies are added as standard entries; no certBodyDefs override is created for stylistic rewrites.
Cert-body overrides (certBodyDefs): Four terms where (ISC)² and ISACA definitions are substantively different now carry per-body definitions:
Risk — ISACA: probability-and-consequence combination framing; (ISC)²: NIST likelihood-and-impact framing.
Incident — ISACA: policy-violation / service-interruption framing; (ISC)²: CIA-jeopardy event framing.
Governance — ISACA: COBIT evaluate-direct-monitor definition including governance-vs-management distinction; (ISC)²: organizational-process framing. (Base entry was corrupted; reconstructed from truncated original.)
Audit — ISACA: formal independent assurance review; (ISC)²: event-logging / activity-recording sense.
Corrupted entry repairs: Controls (fragmented sentence) and Vulnerability (self-referential NVD text) received correct definitions. Both apply equally to all cert bodies — no override needed.
Glued-chain splits: 24 confirmed glued-chain entries were split into their component terms. Embedded copies of terms that already existed as standalone entries were discarded rather than duplicated. Notable extractions: OCTAVE, PASTA, DREAD, LINDDUN (from Threat Modeling), Event type (from a corrupted "Eve nt" entry), RTCP, RTP, ISO, FCPA, SEI-CMM, SSD, and several risk vocabulary terms.
Misfiled content removal: 13 non-glossary entries removed — 9 CISSP domain/task-statement headings, one chapter-summary block (Key Takeaways, 192 words), one worked ALE practice problem (AV—$1250.00), and one sentence fragment. Two misfiled study-guide passages (560-word BCP/DR text under Risk Management; 301-word threat-intelligence passage under Threat Modeling) were replaced with correct, concise definitions.
Duplicate consolidation: 20 same-concept acronym groups collapsed to single entries (AAA×3, SOX×3, DDoS, DoS, DLP×4, RPO×4, MitM×3, ITIL, IAM, GRC, NMS, MTTR, RMF, SD-WAN, TSC, UTM, VoIP, CDMA, GLBA, IPS, ISCM, MAC-mandatory), plus 14 garbage fragment entries removed (KPI Title series, FAULT TOLERANCE malformed term, sentence-fragment stubs). SDLC retained as two entries (Software / System Development Life Cycle) — genuinely distinct concepts.
Missing-term restoration: 61 terms silently dropped in a prior pass were restored with OCR cleanup applied. Glued-together entries were split and fragment terms completed to their canonical full form (e.g., "Man" → Man-in-the-Middle Attack (MITM); "Committee of Sponsoring Organizations of the Treadway" → full COSO entry).
Final glossary: 3,058 entries, zero exact-term duplicates (asserted), 8 cert-body overrides, 21 legitimate acronym shares (all genuine different-concept pairs). Validated by both validate_gloss_overrides.py and validate_gloss_metadata.py check at exit 0.
Full-Text Search Index
The course database schema now includes a content_search FTS5 virtual table populated from every topic's title and block content (HTML tags stripped, SVG included). This index powers Jump Palette keyword search and future in-course search features. The index is populated once at build time and is read-only at runtime.
⚠ Course database file sizes approximately doubled in this release due to the FTS5 index. Download sizes will be larger than prior releases.
Glossary Metadata Schema
glossary_master.json now carries a metadata block with a SHA-256 content checksum, entry count, content version, and timestamp. On load, migrate.py verifies the checksum and reports a warning on mismatch (non-fatal — the build continues). A new validate_gloss_metadata.py tool provides check and bump subcommands for maintaining the metadata block between editing sessions.
Bug Fix — migrate.py Glossary Filter
A defect in migrate.py v3 caused all glossary entries to be silently excluded when the glossary uses the new dict format ({metadata, entries}) and entries carry no per-exam filter field. The filter predicate incorrectly required an exams field on each entry; entries without that field (i.e., universal entries applicable to all exams) evaluated to zero matches. Patched: entries with no exams field are now treated as universal and included in all exam databases.
Glossary Remediation — Additional Content Fixes
A concurrent session's audit and remediation pass targeted specific data-quality patterns beyond the general ALL-CAPS consolidation described above. These fixes were folded into the same 3,079 → 3,058 net reduction:
Term/definition merges: 7 entries had definition prose leaking into the term field. Corrected: Hardware VPN, Host VPN, Site-to-site VPN, Software VPN, INTERNET, PANDEMIC, and RISK (as "Risk (potential)" to avoid conflicting with the primary Risk entry that carries certBodyDefs overrides).
UPS spelling correction: Uninterrupted power supply (UPS) renamed to Uninterruptible power supply (UPS) — the correct industry-standard term. The malformed all-caps duplicate UPS (UNINTERRUPTABLE POWER SUPPLY) was also removed.
ISO three-way disambiguation: kept Information security officer (ISO) and International Organization for Standardization (ISO) as distinct concepts; removed the malformed ISO (INTERNATIONAL STANDARDS ORGANIZATION) duplicate whose expansion was factually wrong (the actual body name uses "Organization for Standardization", not "Standards Organization").
BCP retained as two entries: Business Continuity Plan (BCP) and Business continuity planning (BCP) are distinct concepts in BC literature (artifact vs process) and were kept separate.
Corrupted CIS Controls entries: 52 entries where the term had been broken across the term and defn fields (e.g., term=Conduct, defn=Audit Log Reviews) were concatenated to their intended single-term form.
Cross-reference normalization: 16 See X definitions rewritten to canonical form. All variants (See application firewall., See Digital certificate, See zombie army) now render as See "Application firewall". with consistent quoting, capitalization, and terminal period.
Acronym field extractions: 7 entries whose term ends in a parenthetical acronym but had an empty acronym field were populated (Anti-Tamper AT, Autonomous system AS, Common Criteria CC, Configuration Control CC, Hallucination AI, and two others).
Bare-acronym entries: 48 industry-standard acronyms (BSIMM, CMMC, COBIT, NIST, ISACA, RADIUS, SCADA, STRIDE, TOGAF, ZTNA, and others) had their acronym field populated so all lookups by acronym succeed.
All fixes validated by both validate_gloss_overrides.py and validate_gloss_metadata.py check at exit 0. Final entry count and 8 cert-body overrides match the counts documented above.
Bug Fix — validate_gloss_overrides.py Dict-Format Compatibility
Companion bug to the migrate.py glossary filter fix documented above. The validate_gloss_overrides.py script iterated the loaded JSON directly with for entry in entries, which worked when the glossary was a bare list of entry dicts but crashed with AttributeError once the glossary was wrapped in the {metadata, entries, certBodyDefs} dict — the iterator yielded the top-level keys "metadata", "entries", "certBodyDefs" as strings, and the next line's entry.get("term", ...) failed because strings have no get method.
Patched to handle both formats: if the loaded JSON is a dict with an entries key, use data["entries"]; if it's a bare list, use it directly; otherwise fail with a clear error message. The two format branches are exhaustive and mutually exclusive.
Release 26238_01 — August 26, 2026
Feature release · Program · Requires DB rebuild for full-text search
Application-side feature work across three targets (Blazor Web, MAUI Android, Legacy Node). Three feature sprints delivered together, plus the FTS5 application integration to consume the DB-side index shipped in 26239_01.
Sprint C — Retention System
Review queue. Every completed topic resurfaces on a schedule based on how the learner performed. Intervals: 100 percent with high confidence = 14 days, 100 percent otherwise = 7 days, 67 percent accuracy = 7 days, 33 percent = 3 days, 0 percent = 1 day. A new Review pill in the header nav (Blazor) and a Reviews footer link (Legacy) show the due count.
Review mode. Clicking a due topic opens it with a review banner and a confidence-only slider at the bottom instead of the normal quiz. Re-quizzing was deliberately not offered: memorization contaminates repeat scores after one or two passes. The original quiz record remains intact as the retention baseline; the fresh self-rating is appended to a reviews list on the answer record.
Shaky topics detection. A second section flags topics where self-rating is out of step with observed performance, only when the pattern is completely consistent across all three questions on the topic (all correct at low confidence, or all wrong at high confidence). Underconfident and overconfident are shown separately and grouped by domain.
Launch-time reminder banner. When Start loads with items due, a card at the top shows the count and offers a one-tap Start with reviews button. Chosen deliberately in place of Android push notifications, which would have required requesting permissions and undermined the no-permissions, no-ads, no-accounts, no-telemetry story in the Play Store.
Sprint D — Report Screen Overhaul
Report screen segmentation. Organised into five sub-sections with clear headers: Summary, Performance, Insights, Objectives, Next steps. Both Blazor and Legacy share the layout.
Weakness heatmap. A domain-by-difficulty grid, each cell coloured on an HSL green-to-red ramp based on accuracy. Clicking a cell filters the objectives tree below to just those topics.
Per-domain calibration. Alongside the overall calibration verdict, every domain gets its own row: rated vs scored side by side with a verdict (well-calibrated / overconfident by N pts / underconfident by N pts), colour-coded on the left edge.
Calibration trend over time. Weekly-bucketed dual-line chart using the answeredAt timestamps from Sprint A. Measured proficiency (teal solid) vs self-rating (red dashed) averaged per ISO week. Requires at least two weeks of dated activity before it renders; a hint appears in the meantime.
One-click remediation. Focused remediation card with a drop-down criterion (20 weakest / all below 67 percent / all below 50 percent / overconfident) and a button that jumps the study cursor to the first matching topic. Button label shows the count that will be queued; disabled when nothing matches.
Sprint E — Exam Date and Pace Tracker
Per-exam target date. Collapsible section on the Start screen lets a learner pick a target date for each exam independently. Stored locally per exam (Blazor via ProgressStore preferences, key ea_exam_date_{examCode}; Legacy via localStorage) — no calendar sync, no external service.
Pace card. Once a date is set, a card shows days remaining, objectives left, required topics-per-day to finish, and actual pace over the last seven days. When actual pace falls below 80 percent of required the card turns red and adds a recovery line ("Behind pace. To finish on time you'd need X.X topics/day from here on."). No moralizing text — the number does the talking.
Combined launch banner. The Sprint C reminder banner now covers both feature sets: when both an exam date and reviews are present, the banner reads "9 days to your exam · 25 topics due for review". Either half also shows on its own.
Full-Text Content Search (Application Side)
The Jump palette gains a Search inside topic content too checkbox. When enabled, an async debounced query against the DB-side FTS5 index (shipped in 26239_01) returns topics whose prose contains the search terms, unioned with the existing title/number matches. Uses BM25 relevance ordering, prefix matching (so "zero tru" finds zero trust), and falls back gracefully to title-only search on older course databases lacking the index. Legacy exposes the search via GET /api/{examCode}/search?q= with the same sanitisation logic as the Blazor SearchContentAsync.
Report Screen Segmentation — Legacy Parity
Legacy renderResults now emits the same five section wrappers as Blazor (Summary / Performance / Insights / Objectives / Next steps), matching the visual structure across all three targets.
Not Shipping in This Release
Per-learner-baseline shaky detection — v1 uses naive per-question thresholds. A per-learner baseline is a v2 upgrade once enough per-learner data has accumulated.
True side-quest remediation cursor — v1 sets the main cursor to the first remediation topic. A future refinement would add a separate side-quest sequence that pops back to the main cursor on completion.
Legacy exam-date backup portability — Legacy stores the exam date in localStorage rather than the preferences table, so it doesn't round-trip through the backup/restore feature. Blazor's does.
Upgrade Actions
Rebuild all 20 course DBs with the updated migrate.py to populate the FTS5 index (see 26239_01 release notes). Until you do, the Search inside content toggle silently returns empty and users get title-only search — no error, no data loss.
Release 26237_03 — August 25, 2026
Feature release · Program only · No course content changed
Sprint B — Notes, Notes Report, Examulator Nudge
Per-topic notes UI. A note button appears on the Topic screen next to the topic title. Clicking it opens an inline editor. Notes are stored on the answer record (nullable string, backward-compat) and are visible when reviewing a completed topic.
Notes report screen. A dedicated screen lists every topic with a note, sorted by most recently updated. Reachable from a badge in the header nav that shows the total note count.
Examulator URL nudge. On the Results screen, once a learner has completed a substantial portion of the course, a small card suggests companion product Examulator at certificationtoolanddie.com/examulator for timed practice with a larger question bank. URL link only — no cross-installation.
Release 26237_02 — August 25, 2026
Feature release · Program · Introduces cross-device progress transfer
Sprint A — Timestamps and Backup/Restore
Answer timestamps. TopicAnswer gains two nullable UTC-millisecond fields: AnsweredAt (when the quiz was submitted) and ContentViewedAt (when the reading portion was first viewed). Backward compatible — existing progress records without these fields are treated as timestamp-unknown and everything continues to work.
ProgressBackup service. Blazor gains a Manage progress screen with two-card UI: create a backup (downloads a zip containing progress.json + manifest.json) and restore from backup (upload a zip, choose overwrite or merge mode). Legacy provides equivalent functionality via three endpoints backed by the adm-zip package.
Cross-device username remap. On restore, if the backup's stored username differs from the current device's username, an option offers to remap the imported records to the current username — useful when moving between devices with different logins.
Merge vs overwrite. Overwrite discards existing progress and installs the backup as-is. Merge preserves both, resolving conflicts by taking the more-recent updatedAt per topic.
Dependency Notes
adm-zip ^0.5.16 added to legacy/package.json. Run npm install in the legacy/ folder after upgrading.
Release 26237_01 — August 25, 2026
Program only · No course content changed
ISACA Support & Cert-Body Filter
All — Groundwork for ISACA course support. All eleven ISACA certification tracks are now in the bundled catalog and appear in the exam selector: AAIA, AAIR, AAISM, CCA, CCOA, CCP, CDPSE, CGEIT, CISA, CISM, CRISC. The catalog now holds twenty courses total (9 ISC² + 11 ISACA).
Because twenty cards on one screen would be visually overwhelming, the exam selector gains a small cert-body pill toggle in the top-right of the header: (ISC)² and ISACA. The active segment fills with the accent colour and the list re-renders to show only that certifying body's courses. No intermediary screen was added — the toggle sits above the same card grid learners already use.
Default is (ISC)² for first-time users (higher install-conversion, matches Play Store copy).
Last-selected tab is remembered via the existing preference store (ea_cert_body_filter), so returning learners land back on their chosen body. Blazor uses ProgressStore, Legacy uses localStorage; both share the same key.
New "Not yet available" state. ISACA courses whose DB files haven't been posted to the versions manifest yet render as dim, non-clickable cards labelled "Not yet available" rather than the interactive "Click to download" that would give a 404. The distinction is derived automatically at runtime from RemoteVersion > 0 — no hand-maintained list. As each course DB is uploaded to the manifest, its card lights up on the next selector refresh (5-minute manifest cache).
Header kicker updated to (ISC)² & ISACA Certification Study Tool on the exam selector.
Implementation Notes
ExamInfo gained two computed properties: CertBodyKey (normalised "ISC2" / "ISACA" bucket derived from the displayCertBody string) and IsPublished (RemoteVersion > 0). Neither serialises; both are pure runtime derivations, so no schema changes.
exams.json grew from 9 to 20 entries. New ISACA entries carry certBody: "ISACA" and empty contentRevision (populated at runtime from the DB user_version stamp when installed).
Pill toggle is a two-segment role="tablist" with aria-selected state on each segment.
Legacy re-renders the selector body in place on segment tap rather than doing a full page rebuild.
Release 26232_03 — August 20, 2026
Bug fixes · Program only · No course content changed
Progress Counts Against Exam Objectives, Not Raw Page Count
All — Delivery 26232_01 expanded the study sequence to include domain, chapter, and topic overview pages so learners get context before diving into leaves. That change had knock-on effects in several places that had assumed the sequence length equalled the number of testable objectives — since it no longer does, several counters were mis-comparing leaves against a sequence that included overviews:
Start screen — "Ready to study now" was showing the full sequence length while sitting next to "Exam objectives" showing just leaves, giving two different numbers side-by-side with no explanation. Relabelled to "Total study pages" so the two stats read as complementary rather than confusingly parallel. The saved-progress card now compares completed objectives against total objectives rather than mixing leaves with pages.
Progress screen — completion percentage was under-reporting because the denominator was the whole sequence (leaves + overviews). Restored to a leaves-only denominator.
Text-format results report ("Topics complete: X / Y") had the same mismatch. Fixed.
Screen-reader summaries on Start / Progress / Results announced "N of M topics" with N = leaves completed and M = full sequence. Now announces "N of M objectives" with matching numerators and denominators.
Legacy received all of the above in the equivalent renderStart / renderProgress functions.
None of these bugs affected the actual study flow, scoring, or the persisted state — only the on-screen counters.
Release 26232_02 — August 20, 2026
Enhancements · Program only · No course content changed
MAUI App Icon
MAUI — The Android app icon was rendering as an unreadable blur. Root cause: MauiIcon pointed at Resources/AppIcon/logo.png, which contained the full brand logo including all text. When Android scaled that to launcher-icon sizes (48–96 px), every letter became a smear of pixels. Fixed: replaced with a properly-formed adaptive-icon foreground — just the cap, shield, lock, key, and tassel, centred at ~68% of the 432×432 canvas to fit within Android's inner safe-zone circle. Legible and recognisable at every launcher density.
Version + Build Date on Splash Screens
All — The splash screen now displays the running version and build date in a small monospace footer beneath the copyright line:
Version 26232_02 · Built 2026-08-20 22:00 UTC
Blazor (Web + MAUI Hybrid): the build date is stamped into the ExamAdvantage.Shared assembly at compile time by an AssemblyMetadata("BuildTimestampUtc", ...) attribute injected via MSBuild. A new BuildInfo singleton reads it via reflection, alongside ExamAdvantage:Version from configuration.
Legacy: server.js now stats ExamAdvantage.html at startup and injects the file's mtime into a new APP_BUILD_DATE placeholder. No user action needed — every redeploy refreshes the date automatically.
Release 26232_01 — August 20, 2026
Feature · Program only · No course content changed
Study Sequence Now Includes Overview Content
All — Learners previously jumped straight into terminal leaves (e.g., 1.1.1.a) when starting a new session. The sequence-building code filtered to leaves only, excluding every domain, chapter, and topic overview. Removed the filter so the sequence includes every topic in document order. The existing infrastructure for content-only completion tracking was already fully in place — the fix was one line per target. Existing users' saved progress reconciles transparently.
Back Navigation
All — Added a Previous button on Topic and Quiz screens so learners can walk back through material they've already covered.
Topic screen: ← Previous button (whenever Cursor > 0) steps back one position. Completed topics show a Review questions button that opens the quiz in read-only reveal view.
Quiz screen: ← Previous button appears alongside Back to reading. Disabled during an in-progress quiz until every question has an answer. Once enabled, clicking Previous persists picks on the way out — answers can never be modified after Back.
Advance semantics: Next / Continue distinguishes fresh work (jumps to next unanswered topic) from stepping through previously-completed material (advances one position at a time).
Text-to-Speech Fixes
All — Several TTS bugs collectively made the read-aloud button feel unreliable:
Splash / Begin Studying screen — Toggling audio on did nothing until the next screen appeared. Fixed by priming the audio system on the first user gesture with a capture-phase listener in tts.js.
Non-content screens — The Read button did nothing on Start, Exam Selector, Progress, Bookmarks, Results, and Parent Card screens. AppShell now handles TTS state changes for these directly.
Ghost topic audio after navigating away — Guard added to TopicScreen.OnTtsStateChanged.
Audio doesn't auto-read on page change — AppShell.OnChanged now calls SpeakAsync(ScreenSummaryText()) on every non-Topic transition when TTS is enabled.
Audio killed by QuizScreen dispose race — Removed Tts.StopAsync() from Dispose(); SpeakAsync() internally cancels prior speech.
UI Fixes
The Cancel button in the course-download dialog was disabled while a download was in flight. Fixed by attaching a CancellationTokenSource to InstallAsync().
Clicking Next between content slides didn't scroll back to the top. Added a scrollTop() helper; both AppShell.OnAfterRenderAsync and TopicScreen.AdvanceAsync now call it.
Branding
Replaced the placeholder brand image with the actual EA logo across every surface: Blazor header, Blazor splash, Web favicon, MAUI native splash overlay and app icon, and legacy inline base64 blobs.
Regenerated splash.png (800×717) from the transparent source logo. The logo now floats cleanly on the dark navy body background without a white card or drop shadow.
Removed the redundant logo image from the ExamSelector screen.
Version Format
MAUI — ApplicationDisplayVersion corrected to two-digit form (e.g., 26232.01). Rule documented inline in the .csproj: revisions are always two digits with a leading zero when < 10.
MAUI — ApplicationVersion (Android's versionCode) is now derived in lock-step via (YYDDD × 100) + VV. publishaab.ps1 validates the match and hard-fails the build if they disagree.
Release 26228_01 — August 16, 2026
Bug fixes · Program only · No course content changed
Accessibility Audit Remediation
Fixed muted body-text color: --muted was 4.27:1 in light mode and 3.62:1 in dark mode, both failing WCAG 2.1 AA (4.5:1 required). Corrected to 5.65:1 (light) and 5.53:1 (dark). One design-token change resolves all 33 usages.
Added role="progressbar" with aria-valuenow / aria-valuemin / aria-valuemax / aria-valuetext to the top-of-screen course-progress rail.
Added aria-label to the topic and glossary search inputs.
Added focus trap to all modal overlays (Accessibility panel, Glossary panel, Jump palette, Start Over modal, Install dialog). Tab / Shift+Tab focus stays inside the open dialog; focus is restored to the triggering element on close.
Legacy — Restructured the Start Over modal to remove a select nested inside a button. Dropdowns are now siblings of their associated choice buttons.
Auto-Updater Infinite Loop
Legacy — updater.js determined the locally installed version by regex-scanning ExamAdvantage.html for the EA_VERSION constant. Because the constant in the file on disk is the build-time placeholder APP_VERSION (replaced by server.js only at serve time), the regex never matched, the local version was returned as 0_00, and every launch triggered a download-restart cycle that never resolved. Fixed by reading the version from appsettings.json instead. The filename regex (progRE) was also updated to accept both the legacy underscore format (26226_06.zip) and the current dot-plus-delivery format (26226.06-1.zip).
Start-Over Modal — Dropdown Does Not Activate Choice Button
Legacy — No change listener was attached to the select elements in the "Start over" modal, so choosing a domain or subdomain from a dropdown left the choice button selection unchanged — causing the fresh run to always restart from the beginning. Fixed by adding change listeners that update the active button and mode to match the selection.
Release 26227_01 — August 14, 2026
Feature · Course DBs · Full-corpus quality remediation and content versioning
Question Quality
CISSP: replaced 228 defective distractor options containing generator template boilerplate with properly authored, exam-quality distractors.
Completed 16 truncated option texts across CC, CCSP, CISSP, and ISSEP.
Adjudicated 797 questions where two reviewers disagreed: 793 confirmed correct, 3 answer keys corrected, 1 severely garbled question fully regenerated.
Removed 199 em-dashes from whyWrong fields across 8 exams.
Fixed one instance of banned vocabulary in a CISSP question option.
Glossary
Removed 4 orphaned fragment entries (ARIN, CRISC, CVSS, HIPAA).
Completed or rewrote 30 truncated definitions.
Added 5 missing standard entries: DMARC, MS-ISAC, NSA, SSAE 16, and OCTAVE.
Fixed capitalization error in the "High impact" definition.
Removed erroneous "Towers of Sauron" entry.
Application — Content Versioning
Each study topic now carries a content version stamp in the course database. When a topic's content or questions are updated in a future release, the application will show an Updated — review badge next to that topic in the section overview. The badge will appear for topics studied from this release onward.
Application — Version Check
On loading a course, the application compares the course database version against the installed application version. If the database is older, a warning banner is shown prompting the user to reinstall the course. Users can still study while the mismatch persists.
Release 26226_06 — August 14, 2026
Enhancements · Program only · No course content changed
Component labels: All = all three targets. Legacy = Node.js / HTML single-file app. Razor = ExamAdvantage.Web (Blazor Server). MAUI = ExamAdvantage.Maui (Android Hybrid).
Course Compatibility Enforcement
All — Replaced the previous version check with a per-exam compatibility floor. Program bug-fix releases no longer force course reinstalls. When an installed course database is below the floor, the learner is redirected to the course installer before anything loads.
All nine (ISC)² exams (CC, SSCP, CISSP, CCSP, CGRC, ISSEP, CSSLP, ISSAP, ISSMP) require a minimum course version of 26227_01 due to full-corpus structural realignment.
Print and Share Report
Legacy / Razor — A Print / Save PDF button is now present on the Results screen.
MAUI — Android's WebView does not expose a native print dialog, so the Results screen shows a Share report button that generates a plain-text proficiency summary and presents the Android share sheet.
Application Subtitle
All — Navigation bar subtitle updated from "Exam Preparation Engine" to "Cybersecurity Certification Preparation."
Content Revision Display
Legacy / Razor — The contentRevision field shown in version-mismatch messages is now derived from the installed course database's user_version stamp at runtime, rather than read from a static value in exams.json.
Visual Studio Solution Restructure
Razor / MAUI — Solution files moved to the repository root alongside ea2/ and legacy/. The legacy application source is now represented as a Solution Folder with Solution Items, making all legacy files editable directly from Solution Explorer.
MAUI / Android Improvements
ApplicationDisplayVersion corrected from 26222.1 to 26226.6.
PublishTrimmed=true / TrimMode=partial added for Release builds.
Removed empty MauiFont and MauiAsset item globs referencing directories that do not exist.
Build Script
Razor — build-desktop.sh now passes PublishTrimmed=true and TrimMode=partial for all self-contained platform builds.