|
| 1 | +# Handoff: make lesson ordering cheap to change (Option B) |
| 2 | + |
| 3 | +## Why |
| 4 | +Today, a lesson's **absolute position** is stored as *content* in three places, so |
| 5 | +inserting or moving a lesson is a ~250-edit chore: |
| 6 | + |
| 7 | +- `order:` frontmatter is dense consecutive integers → inserting shifts every later lesson. |
| 8 | +- `title:` embeds the ordinal (`"Lesson 20: State machines as diagrams"`). |
| 9 | +- Cross-references name the ordinal in visible prose and link text |
| 10 | + (`[lesson 12](#/lesson/12-arrays)`, and bare "in lesson 20" mentions). |
| 11 | + |
| 12 | +Sorting is driven **only** by `order` (`site/src/lib/lessons.ts:92`); the numeric |
| 13 | +prefix on folder names is cosmetic. The fix: **derive the displayed number from a |
| 14 | +lesson's position in the sorted list**, and get ordinals out of stored content. |
| 15 | + |
| 16 | +Measured footprint (lessons 1–34): 34 titles, 103 hash-links, 128 prose "lesson NN" |
| 17 | +mentions, 34 numbered folders. |
| 18 | + |
| 19 | +## Scope: Option B (do), Option C (do NOT) |
| 20 | +**In scope (B):** |
| 21 | +1. **Gapped `order`.** Rewrite each lesson's `order` to `position * 10` (current |
| 22 | + 1st → 10, 2nd → 20, … 34th → 340), preserving today's exact sequence but |
| 23 | + leaving room to insert. (A future maze module will slot in at, e.g., 191–195 |
| 24 | + between Objects and State Machines — nothing else will need to move.) |
| 25 | +2. **De-numbered titles.** Strip the `Lesson N: ` prefix from all 34 `title:` |
| 26 | + values → concept only (`title: "State machines as diagrams"`). |
| 27 | +3. **Site renders the number from position.** The `lessons` array is already |
| 28 | + sorted by `order`; display a 1-based index as the lesson number everywhere a |
| 29 | + number should appear — index cards (`LessonCard.tsx`), the lesson header |
| 30 | + (`LessonView`), and the sidebar (`AppSidebar.tsx`, whose `shortTitle` regex on |
| 31 | + line 18 becomes obsolete — titles no longer carry the prefix; prepend the |
| 32 | + derived number instead if a number is wanted there). Numbers must stay 1..34 |
| 33 | + in the same order after the refactor — this is a no-visible-reorder change. |
| 34 | +4. **Reorder-proof cross-references.** This is the point of the whole exercise: |
| 35 | + after this, moving/inserting a lesson must NOT require editing any other |
| 36 | + lesson's prose. Recommended mechanism: a custom link renderer (the site |
| 37 | + renders lesson markdown — find the react-markdown/MD renderer in |
| 38 | + `site/src/`) that, for any `#/lesson/<slug>` link, resolves the target |
| 39 | + lesson's **current** derived number (and/or title) at render time via |
| 40 | + `getLesson(slug)` + its index. Convert the 103 existing |
| 41 | + `[lesson N](#/lesson/<slug>)` links to a canonical slug-keyed form the |
| 42 | + renderer fills in, so the visible "lesson N" is always computed, never stored. |
| 43 | + For the bare-prose "lesson NN" mentions that are not links, prefer turning them |
| 44 | + into such links, or rephrase to a concept reference ("the arrays lesson"). No |
| 45 | + stored ordinal may remain in prose. |
| 46 | + |
| 47 | +**Out of scope (Option C — do NOT do):** |
| 48 | +- Do **not** rename lesson folders or strip numeric prefixes from slugs. |
| 49 | +- Do **not** change any `#/lesson/<slug>` href target. Slugs stay exactly as they |
| 50 | + are (their numeric prefix is now a harmless opaque id users never see). |
| 51 | + |
| 52 | +## Deliverables |
| 53 | +- All 34 lessons updated (order + title) and cross-references converted. |
| 54 | +- Site code renders derived numbers and resolves cross-ref numbers at render time. |
| 55 | +- `docs/adr/0001-derive-lesson-order-from-position.md` recording the decision |
| 56 | + (context: ordinal-as-content churn; decision: derive from position, concept-only |
| 57 | + titles, slug-keyed cross-refs; consequence: inserts/reorders touch only `order`). |
| 58 | +- `cd site && npm run build && npm run lint` both pass. |
| 59 | + |
| 60 | +## Acceptance check |
| 61 | +- Index and sidebar show lessons 1..34 in the identical order and with the same |
| 62 | + visible numbers as before this change. |
| 63 | +- Every cross-reference link still resolves, and its visible number matches the |
| 64 | + target's current position (test by temporarily bumping one lesson's `order` |
| 65 | + past a neighbor — the reference text should follow automatically, with no |
| 66 | + content edit — then revert). |
| 67 | +- No `title:` contains `Lesson \d+:`; no lesson prose contains a hard-coded |
| 68 | + "lesson NN" ordinal. |
0 commit comments