Skip to content

Daily review 2026-07-03 - #68

Draft
NghaReformer wants to merge 2 commits into
mainfrom
daily-review/2026-07-03
Draft

Daily review 2026-07-03#68
NghaReformer wants to merge 2 commits into
mainfrom
daily-review/2026-07-03

Conversation

@NghaReformer

@NghaReformer NghaReformer commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Daily Review — 2026-07-03

1. Bugs & Issues (18 findings)

BUG-01 · Critical · src/routes/[lang]/playgrounds/[slug]/+page.svelte:103

{#await} block missing {:catch} — silent failure on playground load error

{#await nativeLoader} has {:then} but no {:catch error}. If the dynamic import fails (network error, Vite chunk not found), the user sees a permanently blank panel with no error message.

Fix: Add {:catch err} with an error card using var(--error) and $t('error.generic'), and console.error(err).


BUG-02 · High · 10 files — --orange, --blue, --red not in css-generator.ts

34 usages of undefined CSS custom properties always fall back to hardcoded hex

css-generator.ts emits --amber, --error, --accent — not --orange, --blue, --red. All 34 references silently use their hex fallbacks, bypassing the theme system.

Undefined Fallback Correct token
--orange #f59e0b --amber
--red #ef4444 --error
--blue #3b82f6 needs adding, or use --accent

Affected: KpiStrip.svelte:76, amortization/ScheduleTable.svelte:240,246,259,265, amortization/InputsPanel.svelte:604,605, amortization/ChartPanel.svelte (9 lines), bank-reconciliation/LedgerPanel.svelte:175, bank-reconciliation/VarianceScale.svelte (6 lines), bank-reconciliation/TransactionJournal.svelte, bank-reconciliation/ScenarioWalkthrough.svelte.

Fix: Either alias --orange/--blue/--red to existing tokens in css-generator.ts, or rename all call sites to use the correct tokens (preferred).


BUG-03 · High · src/lib/playgrounds/bank-reconciliation/components/CategoryBreakdownDonut.svelte:31–39

9 hardcoded hex colors in a JS object — completely outside the theme system

const CATEGORY_COLORS = { 'outstanding-check': '#6ea8fe', 'bank-charge': '#f59e0b',}

Passed to style="background: {seg.color}" (line 120). Not themeable; several duplicate existing tokens.

Fix: Read CSS tokens at mount via getComputedStyle(document.documentElement), or assign CSS classes per category and use var() / fill: currentColor in scoped styles.


BUG-04 · High · src/app.html:1

<html lang="en"> hardcoded — SSR delivers wrong language for French routes

The layout's $effect fixes this client-side only. During SSR, /fr/* pages are served lang="en" in raw HTML, misleading screen readers and search indexers.

Fix: In hooks.server.ts, detect locale from event.url.pathname in the handle hook and inject via resolve(event, { transformPageChunk: … }).


BUG-05 · High · src/routes/[lang]/privacy/+page.svelte

Entire privacy page is hardcoded English — /fr/privacy renders untranslated

import { t } from '$lib/i18n' is present but never called. All six <h2> headings and body paragraphs are raw English strings.

Fix: Create privacy.en.ts / privacy.fr.ts namespaces, register them, and replace all hardcoded strings with $t().


BUG-06 · High · src/lib/components/playground/PlaygroundTabs.svelte

Tab buttons lose their accessible name on mobile

At ≤480 px, .tab-label { display: none } hides the text; the icon <span> already has aria-hidden="true". The <button role="tab"> has no accessible name for screen readers on small screens.

Fix: Use .visually-hidden (already in app.css) instead of display: none, or add aria-label={$t(tab.labelKey)} to the button.


BUG-07 · Medium · src/lib/playgrounds/cvp/components/ChartToolbar.svelte:135,141

--overlay-color is not in the theme; its two fallback values conflict

background: var(--overlay-color, var(--text-muted));   /* line 135 */
color:      var(--overlay-color, var(--accent));        /* line 141 */

--overlay-color is never defined. The differing fallbacks mean the same variable would render two completely different colors if ever set.

Fix: Remove --overlay-color and use --text-muted / --accent directly in separate rules.


BUG-08 · Medium · src/lib/components/playground/ExercisePanel.svelte:11–13

Difficulty labels hardcoded in French in a shared component

fondamental: { label: 'Fondamental',},
intermediaire: { label: 'Intermédiaire',},

English users see French labels. Keys already exist in the amortization and journal-entry namespaces.

Fix: Promote to shell.difficulty.* in common.en.ts / common.fr.ts and replace with $t().


BUG-09 · Medium · src/lib/components/Nav.svelte:16,28

Hardcoded English aria-label attributes not i18n'd

aria-label="Main navigation" and aria-label="Toggle menu" are announced by screen readers and must be translated.

Fix: Add nav.ariaLabel / nav.toggleMenu to common.en.ts / common.fr.ts.


BUG-10 · Medium · src/routes/[lang]/chart-of-accounts/+page.svelte:134,153

Two ARIA role violations on filter controls

  1. Line 153: Filter chips are in role="tablist" but children have no role="tab" — ownership violation. These are mutually exclusive filters; role="radiogroup" / role="radio" is correct.
  2. Line 134: Framework switcher uses role="radiogroup" / role="radio" correctly but all four buttons are independently Tab-focusable. ARIA spec requires roving tabindex (only the active radio in tab order; siblings navigated by arrow keys).

Fix: Switch chips to role="radiogroup". Implement roving tabindex on the framework switcher.


BUG-11 · Medium · src/lib/components/WaitlistForm.svelte:55

Inline style on honeypot <div> violates no-inline-styles rule

<div style="position:absolute;left:-9999px;opacity:0;height:0;overflow:hidden;" aria-hidden="true">

Technique is valid; the rule is not.

Fix: Move to a scoped .hp-trap { position: absolute; left: -9999px; … } class.


BUG-12 · Medium · Amortization + Interest playgrounds

CSS transition/animation without prefers-reduced-motion guard

Bank-reconciliation consistently wraps animations in @media (prefers-reduced-motion: reduce). This guard is absent from the interest playground components and the spinner @keyframes spin in [slug]/+page.svelte:303.

Fix: Mirror the bank-reconciliation pattern in the affected components.


BUG-13 · Low · src/lib/i18n/namespaces/playgrounds.fr.ts:21

French translation has grammatical error and semantic mismatch

'pg.journal-entry.desc': 'Calculateur de écritures comptables.'
de must contract to d' before a vowel. "Calculateur" also misrepresents an interactive journal.

Suggested fix: "Tenue de journal comptable en partie double avec le plan SYSCOHADA."


BUG-14 · Low · src/lib/components/playground/NumberField.svelte:100, bank-reconciliation/components/InputsPanel.svelte:60,91

--bg-input and --spacing-md not in the theme token set

Both have working CSS fallbacks but cannot be overridden by future theme changes.

Fix: Add to tokens.ts / css-generator.ts, or remove the primary reference and use the fallback values directly.


BUG-15 · Low · src/lib/components/feedback/FeedbackLauncher.svelte:12, ScreenshotCapture.svelte:16

onMount used in runes-mode components — non-idiomatic Svelte 5

Both files use $state() (runes mode) but call onMount. Functionally correct but $effect is the idiomatic Svelte 5 equivalent.

Fix: Replace onMount(() => { …; return cleanup }) with $effect(() => { …; return cleanup }).


BUG-16 · Low · src/lib/components/playground/PlaygroundSettings.svelte:94

Hardcoded accent hex inside SVG data URI

stroke='%237c7fff' decodes to #7c7fff — the current --accent token. Will silently drift if the accent changes.

Fix: Generate the SVG string at runtime from a JS token reference, or add a comment documenting the coupling with tokens.ts.


BUG-17 · Low · src/lib/playgrounds/journal-entry/components/EntryHistory.svelte:400

color: #fff hardcoded on .btn-confirm

Will fail WCAG AA contrast in any light-mode or high-contrast theme.

Fix: Replace with color: var(--text-primary).


BUG-18 · Low · src/lib/playgrounds/bank-reconciliation/components/CategoryBreakdownDonut.svelte:120

Dynamic inline style binding serialises hardcoded hex into the DOM

<span class="legend-swatch" style="background: {seg.color}"></span>

Compounds BUG-03. Resolves when BUG-03 is fixed.


2. New Playground Ideas

Existing native modules: TVM, Amortization, Bank Reconciliation, Journal Entry, Interest Lab
Existing static iframes: CVP, Depreciation


IDEA-01 — Inventory Valuation Methods

EN: Inventory Valuation Methods | FR: Méthodes d'évaluation des stocks
Target: Licence 2 / Licence 3

Pedagogical objective: SYSCOHADA (class 3) uses CMUP (weighted average cost) as the primary method; IFRS also permits FIFO. Students confuse the methods and cannot explain why profit differs between them under inflationary vs deflationary price trends.

Core interaction: Learner enters 3–6 purchase lots (qty, unit cost) and a series of sales. A side-by-side table shows moving CMUP (SYSCOHADA default), periodic CMUP, and FIFO — closing stock value, COGS, and gross margin per method. A live chart shows margin divergence as the price trend changes.

Inputs/Outputs: Purchase lots, sales lots, period toggle → closing stock value, COGS, gross margin per method, journal entries (class 3 ↔ 6).

Why it complements existing playgrounds: Journal Entry covers the mechanics of stock entries; this teaches what value fills those entries — the upstream decision JE assumes as given.


IDEA-02 — Financial Ratio Analyzer

EN: Financial Ratio Analyzer | FR: Analyseur de ratios financiers
Target: Licence 3 / Master 1 / practicing professional

Pedagogical objective: Students recite ratio formulas but cannot interpret a real set of financial statements. This playground builds diagnostic intuition: is a current ratio of 1.2 safe or dangerous? It depends on industry and receivables quality.

Core interaction: Learner enters simplified SYSCOHADA-format balance sheet and income statement line items (classes 1–5). The playground computes 12–15 ratios grouped by category (liquidity, solvency, profitability, activity) and colour-codes each against sector benchmarks (commerce, manufacturing, services, agriculture — OHADA zone norms). A radar chart shows the overall financial profile.

Inputs/Outputs: ~18 financial statement line items, sector selection → ratios with colour-coded assessment, radar chart, narrative diagnostic.

Why it complements existing playgrounds: Downstream from Journal Entry + Bank Reconciliation — the learner sees what all those entries aggregate into.


IDEA-03 — Budget Variance Analyzer

EN: Budget Variance Analyzer | FR: Analyseur d'écarts budgétaires
Target: Licence 3 / Master 1 / management accountant

Pedagogical objective: Students conflate "favourable variance" with "good", which breaks when a favourable volume variance masks a degraded margin mix. Fixes the core misconception in SYSCOHADA compta analytique (section 9).

Core interaction: Learner enters budget and actual figures for volume, price, variable cost/unit, and fixed costs. The playground decomposes total profit variance into four components shown in a waterfall chart. A what-if mode isolates one driver while holding others constant.

Inputs/Outputs: Budget + actual values for 4 drivers → 4 variance components, waterfall chart, favourable/adverse flags, management commentary template.

Why it complements existing playgrounds: Connects to CVP (which sets up the cost structure) and adds the temporal managerial-control dimension CVP's static break-even analysis lacks.


IDEA-04 — Payroll & Social Charges

EN: Payroll & Social Charges | FR: Calcul de la paie et des charges sociales
Target: Licence 2 / practicing bookkeeper / HR administrator

Pedagogical objective: Payroll is the highest-frequency bookkeeping task in OHADA-zone SMEs. Students cannot split gross salary into CNPS employee/employer shares, compute IRPP brackets, or produce the journal entries (accounts 421, 431, 437, 447). Rates vary by country; the playground makes this explicit.

Core interaction: Learner selects country (Cameroon, Côte d'Ivoire, Sénégal, or generic), enters gross salary, benefits in kind, and dependants. The playground computes net salary, employee deductions (CNPS + IRPP), employer charges (CNPS + FDFP), and total wage cost. A journal entry panel shows the salary booking entry and payment entry.

Inputs/Outputs: Country, gross salary, benefits, dependants → deductions itemised, net pay, total labour cost, 2 journal entries, payslip summary.

Why it complements existing playgrounds: Journal Entry covers mechanics; this provides a real, high-frequency context that auto-fills realistic amounts — bridging abstract accounting rules to the monthly HR workflow every OHADA-zone SME performs.


IDEA-05 — Fixed Asset Disposal & Revaluation

EN: Fixed Asset Lifecycle | FR: Cycle de vie d'une immobilisation
Target: Licence 3 / Master 1

Pedagogical objective: Asset disposal is the most frequently mis-journalised event in SYSCOHADA practical exams. Students struggle with three scenarios: at book value (no gain/loss), above (class 77 gain), below (class 67 loss). Revaluation adds a fourth complexity. The existing Depreciation playground stops at end of useful life; this picks up from there.

Core interaction: Learner enters asset cost, acquisition date, depreciation method/rate (compatible with Depreciation playground output), disposal date, and proceeds. The playground computes book value at disposal, gain/loss, and generates the full disposal journal entry. A Revaluation tab applies a price index and shows the resulting equity reserve entry.

Inputs/Outputs: Acquisition cost/date, depreciation method, disposal date + proceeds → cumulative depreciation, book value, gain/loss, disposal journal entry, optional revaluation entry — all using SYSCOHADA class 2/6/7 accounts.

Why it complements existing playgrounds: Closes the lifecycle loop that Depreciation opens. Together they give end-to-end coverage of a fixed asset — the three canonical SYSCOHADA exam questions.

@vercel

vercel Bot commented Jul 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ohadalearn Ready Ready Preview, Comment Jul 3, 2026 11:19pm

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.

2 participants