Skip to content

Daily review 2026-06-28 - #63

Draft
NghaReformer wants to merge 1 commit into
mainfrom
daily-review/2026-06-28
Draft

Daily review 2026-06-28#63
NghaReformer wants to merge 1 commit into
mainfrom
daily-review/2026-06-28

Conversation

@NghaReformer

Copy link
Copy Markdown
Owner

Daily Review — 2026-06-28

Reviewer: automated · Model: claude-sonnet-4-6 · Branch: daily-review/2026-06-28


1. Bugs & Issues

CRITICAL

C-1 · Server-type import in client component

File: src/lib/components/feedback/FeedbackForm.svelte:7
Severity: Critical

import type { FeedbackType, FeedbackSeverity } from '$lib/server/db/types';

FeedbackForm.svelte is a client-rendered Svelte component. Importing — even as import type — from $lib/server/ violates the SvelteKit server-only boundary that CLAUDE.md mandates. While TypeScript erases import type at compile time, SvelteKit's Vite plugin performs static-path analysis and can reject this import, producing a build error in strict mode. More importantly, it breaks the architectural rule: client code must never reference $lib/server/ paths.

Fix: Move FeedbackType and FeedbackSeverity to a shared (non-server) types file — e.g., src/lib/contracts/feedback.ts — and import from there in both the server module and the component.


HIGH

H-1 · Hardcoded French difficulty labels (i18n violation)

File: src/lib/components/playground/ExercisePanel.svelte:11–13
Severity: High

const difficultyMeta = {
    fondamental:  { label: 'Fondamental',   ... },
    intermediaire:{ label: 'Intermédiaire', ... },
    avance:       { label: 'Avancé',        ... },
};

ExercisePanel renders these labels as visible UI text (line 44). English-locale users see French strings. All user-facing strings must route through $t() per CLAUDE.md.

Fix: Add keys such as shell.difficulty.fondamental, shell.difficulty.intermediaire, shell.difficulty.avance to both EN/FR shell namespace files, then replace the hardcoded strings with $t(...) calls (or store the i18n key instead of the label and call $t(key) at render time).


MEDIUM

M-1 · Inline style on honeypot field (CLAUDE.md ban)

File: src/lib/components/WaitlistForm.svelte:55
Severity: Medium

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

CLAUDE.md's first design rule is "No inline styles." The sibling component FeedbackForm.svelte already implements the correct pattern using a .hp CSS class (lines 264–270). WaitlistForm should follow the same convention.

Fix: Remove the inline style attribute; add a .hp rule to WaitlistForm's <style> block mirroring FeedbackForm's implementation.


M-2 · avance difficulty glow token mismatch

File: src/lib/components/playground/ExercisePanel.svelte:13
Severity: Medium

avance: { label: 'Avancé', color: 'var(--error)', glow: 'var(--amber-glow)' },

The dot color is var(--error) (red) but the glow is var(--amber-glow) (yellow). The glow is applied as the badge background; users see a red dot beside a yellow-tinted badge. This is a visual inconsistency likely caused by a copy-paste from the intermediaire entry.

Fix: Change glow to var(--error-glow) (or the red-family glow token defined in tokens.ts).


M-3 · Hardcoded user-facing string on landing page

File: src/routes/[lang]/+page.svelte:28
Severity: Medium

<span class="hero-badge">SYSCOHADA Revisé 2017</span>

This is a visible user-facing label not routed through $t(). All such strings must be bilingual per CLAUDE.md.

Fix: Add hero.badge key to both en and fr landing namespace files (SYSCOHADA Revised 2017 / SYSCOHADA Révisé 2017) and replace with {$t('hero.badge')}.


M-4 · requestFullscreen() rejection leaves isFullscreen stale

File: src/routes/[lang]/playgrounds/[slug]/+page.svelte:44–52
Severity: Medium

function toggleFullscreen() {
    if (!document.fullscreenElement) {
        target.requestFullscreen(); // async — not awaited
        isFullscreen = true;        // set optimistically before resolution
    } else {
        document.exitFullscreen();
        isFullscreen = false;
    }
}

requestFullscreen() returns a Promise that can reject (browser permission denied, element not in DOM, etc.). When it does, the browser fires fullscreenerror, not fullscreenchange, so the existing fullscreenchange listener on line 57 does not reset isFullscreen. The UI then shows "Exit Fullscreen" when no fullscreen is active.

Fix: await target.requestFullscreen() inside an async function and catch the rejection to reset isFullscreen = false. Alternatively, derive isFullscreen solely from the fullscreenchange listener and remove the optimistic assignment.


LOW

L-1 · Emoji icons in tab bar (CLAUDE.md ban)

File: src/lib/components/playground/PlaygroundTabs.svelte:12–14
Severity: Low

{ key: 'learn',      labelKey: 'shell.tab.learn',      icon: '📖' },
{ key: 'playground', labelKey: 'shell.tab.playground', icon: '🧮' },
{ key: 'scenarios',  labelKey: 'shell.tab.scenarios',  icon: '📋' },

CLAUDE.md rule: "No emoji icons." These are rendered as <span class="tab-icon"> in the live UI.

Fix: Replace with inline SVG icons consistent with the rest of the design system, which already uses SVGs everywhere else.


L-2 · Mobile nav missing aria-controls / id binding

File: src/lib/components/Nav.svelte:23–33, 35
Severity: Low
The hamburger <button> has aria-expanded={mobileOpen} but no aria-controls attribute pointing to the collapsible menu div. The .nav-body div has no id. Screen readers cannot programmatically associate the button with the content it controls.

Fix: Add id="nav-menu" to .nav-body and aria-controls="nav-menu" to the hamburger button.


L-3 · Magic-number nav height in playground page

File: src/routes/[lang]/playgrounds/[slug]/+page.svelte:142
Severity: Low

.pg-wrapper { height: calc(100vh - 60px); }

The 60px value hard-codes the nav height defined in Nav.svelte:72. If nav height changes, this breaks silently.

Fix: Define --nav-height: 60px as a CSS custom property in tokens.ts and use calc(100vh - var(--nav-height)) here and in Nav.svelte.


2. New Playground Ideas

Checked against existing coverage: amortization, bank reconciliation, cost-volume-profit, interest, journal entry, time value of money, depreciation (static HTML). None of the proposals below duplicate these.


P-1 · Balance Sheet Builder

EN: Balance Sheet Builder | FR: Constructeur de Bilan

Target learner: Licence 1 / Licence 2

Pedagogical objective: Students memorise account classifications without understanding why assets must equal liabilities + equity. This playground forces them to manipulate both sides of the equation in real time, building intuition for SYSCOHADA's Class 1–5 structure.

Core interaction: A split ledger shows a partial set of account balances. The learner drags each account to the correct bilan section (actif immobilisé, actif circulant, dettes financières, capitaux propres). A live running total shows Assets vs. Liabilities + Equity; the submit button unlocks only when the equation balances.

Minimum viable inputs/outputs:

  • Input: 8–12 pre-seeded account balances (amounts configurable by scenario)
  • Output: Validation of placement, algebraic balance check, colour-coded diff for wrong placements

Complements existing playgrounds: Journal Entry teaches recording; this teaches reporting. Together they cover the full cycle from transaction to financial statement.


P-2 · Financial Ratios Interpreter

EN: Ratios Dashboard | FR: Tableau de Bord des Ratios

Target learner: Licence 3 / Master / Practicing professional

Pedagogical objective: Fix the misconception that ratio analysis is just plugging numbers into formulas. Learners must interpret whether a ratio signals health or distress in the OHADA context, where benchmarks differ from IFRS markets.

Core interaction: The learner enters a simplified income statement and balance sheet (or loads a scenario preset). The playground computes 8 ratios across liquidity, solvency, and profitability categories. Each ratio card shows the computed value, a SYSCOHADA-typical benchmark range, and a colour-coded health indicator. Hovering reveals the formula derivation.

Minimum viable inputs/outputs:

  • Input: ~15 balance sheet line items + 5 P&L items
  • Output: 8 ratio cards with value, benchmark band, traffic-light status, formula tooltip

Complements existing playgrounds: CVP and TVM deal with planning-phase numbers; Ratios deal with post-period performance analysis.


P-3 · Inventory Valuation Comparator (FIFO vs CMUP)

EN: Inventory Valuation | FR: Valorisation des Stocks

Target learner: Licence 2 / Licence 3

Pedagogical objective: SYSCOHADA mandates CMUP by default, but exam questions frequently require FIFO comparison. Most students cannot explain why the two methods produce different COGS figures.

Core interaction: The learner enters a sequence of purchase lots and sale events. The playground renders a parallel table showing running inventory valuation under both FIFO and CMUP, with each movement's impact highlighted. A summary line shows ending stock value and COGS per method, with the delta called out.

Minimum viable inputs/outputs:

  • Input: Up to 10 purchase/sale rows (date, quantity, unit price)
  • Output: Two side-by-side running valuation tables; ending stock and COGS summary per method; delta panel

Complements existing playgrounds: Journal Entry shows how to record an inventory purchase; this shows which value to record and why it differs by method.


P-4 · Cash Flow Statement Builder (Indirect Method)

EN: Cash Flow Statement | FR: Tableau des Flux de Trésorerie (TAFIRE)

Target learner: Licence 3 / Master

Pedagogical objective: Students can read a bilan and compte de résultat but cannot construct the TAFIRE from them. The indirect method reconciliation is consistently the hardest SYSCOHADA financial reporting topic.

Core interaction: The learner is given N-1 and N balance sheets plus the income statement. They classify each line-item change into Operating / Investing / Financing activities and mark adjustments as add-back or deduction. A running total shows net change in cash; final validation compares it to the balance sheet's cash delta.

Minimum viable inputs/outputs:

  • Input: Two balance sheet snapshots + income statement (~20 line items)
  • Output: Populated TAFIRE with correct/incorrect highlighting; net cash reconciliation

Complements existing playgrounds: Closes the financial statement cycle opened by Journal Entry and Balance Sheet Builder (P-1).


P-5 · OHADA-Zone Payroll Calculator

EN: Payroll Calculator | FR: Calculateur de Paie

Target learner: Licence 3 / Master / Practicing professional

Pedagogical objective: Payroll accounting is required in every SYSCOHADA entity but rarely taught interactively. Learners confuse gross salary, taxable base, CNPS contributions, and net-to-pay — and cannot produce the Class 6 journal entries automatically.

Core interaction: The learner inputs an employee's gross salary and selects an OHADA member state to load that country's CNPS and IRPP/IPTS rate tables. The playground computes employer/employee contributions, taxable income, tax, and net salary. A "Generate Journal Entry" button produces the debit/credit structure for accounts 661x/431x/447x.

Minimum viable inputs/outputs:

  • Input: Gross salary, member state selector, optional allowances (transport, housing)
  • Output: Payslip breakdown (gross → deductions → net); journal entry draft; country-specific rate display

Complements existing playgrounds: Journal Entry provides the recording mechanics; this playground provides the payroll-specific figures that feed into them.


End of report — 2026-06-28


Generated by Claude Code

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RwbvNVRKyphRz4LziZQ38b
@vercel

vercel Bot commented Jun 28, 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 Jun 28, 2026 11:09pm

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