feat(percorsi): percorsi personalizzati — libro unico + codice deterministico - #14
Merged
Conversation
…bitmask, plugin curriculum (fase 1) Fase 1 del design pm/design-percorsi-personalizzati.md (milestone m9): - curriculum/toc/<volume>.js: albero sidebar unico per volume (unione dei percorsi it/liceo/its), fonte unica per sidebar e manifest - curriculum/presets.js: IT/Liceo/ITS come selezioni curate - curriculum/manifest.json: posizioni di bit per epoca; epoca corrente append-only, epoche passate immutabili (i codici non scadono mai) - src/lib/curriculumCode.ts: codec puro PDB1-… (Crockford base32, CRC-8, varint LEB128); l'encoder emette il più corto tra bitmask e RLE - plugins/curriculum: walk TOC + titoli dal frontmatter, append automatico al manifest in dev, build prod fallisce se il manifest è incompleto, validazione preset, setGlobalData per il client Verifica: round-trip esaustivo del codec (N≤10 completo + random N=65535), CRC intercetta 496/496 typo a singolo carattere, build prod verde e rossa come atteso rimuovendo un'entry dal manifest. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019y4SRapHyeCQ2EGaNxQeas
- sidebars/<volume>.ts: una sola sidebar `libro` che require() l'albero condiviso da curriculum/toc/ (assunzione CJS-in-TS confermata dalla build). Il vecchio sistema degrada a no-op da solo: PathSelector si nasconde con ≤1 sidebar, DocRoot ricade sul default se la sidebar salvata non esiste. - src/contexts/CurriculumContext.tsx: codice canonico in localStorage `pdb:curriculum`, idratazione a due passate SSR-safe, sync cross-tab, decodifica memoizzata contro il manifest a epoche → ReadonlySet delle chiavi incluse; `?percorso=CODE` viene validato, normalizzato, persistito e rimosso dall'URL (history.replaceState). - Root.tsx: CurriculumProvider (PathProvider resta fino alla fase 4). - curriculumCode.ts: reason `epoch` per i codici di epoche future. Verifica sul build servito: sidebar unica completa, PathSelector sparito, ?percorso= accetta anche codici "sporchi" (minuscole, spazi, O/I per 0/1) e li canonicalizza; codice invalido → warn senza persistenza né crash; nessun warning di idratazione in console. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019y4SRapHyeCQ2EGaNxQeas
…fase 3) - src/lib/curriculumFilter.ts: filterSidebarItems (ricorsivo, elimina le categorie svuotate, preserva link non-doc) + flattenSidebarLinks per la paginazione (categoria con href prima dei figli, come il nativo). - DocRoot: con percorso attivo filtra la PropSidebar del volume corrente; SSR-safe (primo render = included null = libro intero). Via la logica PathContext a sidebar multiple. - DocPaginator (wrapper di @theme-original): senza percorso passthrough; con percorso ricalcola prev/next dalla sidebar già filtrata; doc fuori percorso → nessun paginator. - OffCurriculumBanner (sostituisce OffPathBanner in DocItem/Content): lezione esclusa aperta via link diretto → contenuto leggibile + avviso con «Vedi tutto il libro» (clear live) e «Gestisci percorso» (anchor semplice finché /percorso non esiste, fase 4). Verifica E2E sul build servito: la sidebar nasconde la lezione esclusa, prev/next la salta (perché-gli-oggetti → metodi-di-classe saltando classi-e-istanze), l'URL diretto mostra contenuto + banner senza paginator, «Vedi tutto il libro» ripristina sidebar/paginator/banner live senza navigare e pulisce localStorage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019y4SRapHyeCQ2EGaNxQeas
… vecchio sistema (fase 4) - src/pages/percorso.tsx (+ css module): pagina a doppio ruolo. Studente: campo codice + Attiva, errori mirati per reason (crc/epoch/…), stato attivo con targhetta, «Inizia a studiare», «Rimuovi percorso». Docente: albero volume → capitolo (tri-state) → lezione con le sempre-visibili spuntate e disabilitate, preset IT/Liceo/ITS + «Libro intero» + «Importa il codice attivo», targhetta live sticky con conteggio lezioni, «Copia codice» e «Copia link» (?percorso=CODE). - src/lib/curriculumSelection.ts: codeFromKeys/keysFromCode condivisi tra context, pagina e indicatore (il context ora valida via keysFromCode). - CurriculumIndicator: chip navbar (slot center) con label del preset se il codice canonico coincide (confronto stringa), altrimenti «Percorso attivo»; link a /percorso, «×» per rimuovere. Sostituisce PathSelector. - OffCurriculumBanner: «Gestisci percorso» ora è un <Link> vero. - Rimossi PathContext, pathLabels, PathSelector, OffPathBanner; Root.tsx resta col solo CurriculumProvider. Verifica: typecheck/lint/build verdi; SSR di /percorso corretto (header, card studente, albero completo, targhetta con il codice canonico identico a quello del test Node del codec). Interattività della pagina (tri-state, copia, preset) da verificare a mano nel browser: l'estensione Chrome si è disconnessa durante l'E2E. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019y4SRapHyeCQ2EGaNxQeas
…ebsocket-driver - «Mostra QR» nel pannello codice di /percorso: overlay a tutto schermo pensato per la proiezione in classe — targa bianca (contrasto e quiet zone anche in dark), QR grande del link condiviso (?percorso=CODE) e codice in chiaro sotto per chi digita. Libreria `qrcode` (SVG generato client-side, nessuna risorsa esterna). Chiusura con Esc, «×» o click fuori; scroll-lock e reduced-motion rispettati. - Security: override "websocket-driver": "^0.7.5" per la nuova advisory critical GHSA-mp7j-qc5w-4988 (catena webpack-dev-server → sockjs, solo dev-server). npm audit torna a 0 critical (48 residue, dev/build-time). Verifica in browser sul build servito: overlay apre con QR SVG e codice, Esc chiude e ripristina lo scroll; typecheck/lint/build verdi. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019y4SRapHyeCQ2EGaNxQeas
…se 5) - scripts/check-manifest-append-only.js (npm run curriculum:check): confronta curriculum/manifest.json con origin/main — epoche passate immutabili, epoca corrente append-only (prefisso), currentEpoch può solo restare o avanzare di 1 con la nuova lista presente. Ref senza manifest → check saltato. Cablato in test-deploy.yml prima del lint. - scripts/curriculum-new-epoch.js (npm run curriculum:new-epoch): rito annuale — rigenera l'elenco dalla TOC in ordine curricolare senza tombstone come epoca N+1, congela la precedente (i codici distribuiti restano validi); no-op con avviso se l'epoca corrente coincide già con la TOC (--force per forzare). - plugins/curriculum: esporta flattenTocDocIds per lo script. Testati entrambi: guardia OK su identico e append, VIOLAZIONE su riordino; new-epoch no-op su manifest allineato, apertura epoca 2 con tombstone eliminato e epoca 1 congelata. Aggiornati anche CLAUDE.md e lo skill nuovo-capitolo (non tracciati: .claude/ e CLAUDE.md sono gitignorati) — le lezioni nuove si aggiungono in curriculum/toc/<volume>.js. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019y4SRapHyeCQ2EGaNxQeas
Milestone m9 completa: tutte le 5 fasi (data layer, sidebar unica + CurriculumContext, filtro, configuratore, guardia CI append-only). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
/percorsodove il docente seleziona lezioni/capitoli e ottiene un codice deterministico (PDB1-…) da distribuire agli studenti.npm run curriculum:new-epoch), payload RLE/bitmask Crockford-base32 con CRC-8, guardia CI append-only (npm run curriculum:check).PathContext,pathLabels,PathSelector,OffPathBanner).Fasi (design chiuso in
pm/design-percorsi-personalizzati.md, milestone m9)curriculum/toc/*.js,manifest.jsona epoche, codecsrc/lib/curriculumCode.ts,plugins/curriculumCurriculumContext(localStorage,?percorso=da URL, SSR-safe)curriculumFilter.ts,DocRoot,DocPaginator,OffCurriculumBanner/percorso(checkbox tri-state, preset IT/Liceo/ITS, copia codice/link, QR per la LIM),CurriculumIndicatorin navbar, rimozione vecchio sistemanuovo-capitoloInclude anche il fix critical su
websocket-driver(override inpackage.json, commitae05f61).Bump versione: 0.12.0 → 0.13.0 (feature multi-fase).
Test plan
npm run buildpassa (manifest completo, nessuna lezione mancante)npm run curriculum:checkpassa in CI (test-deploy.yml)?percorso=, sidebar/paginatore filtrati, banner fuori percorso, chip navbarmain🤖 Generated with Claude Code