From 9b22ac0db5d1ddf23ee763ea3801ea8176e5cc03 Mon Sep 17 00:00:00 2001 From: Michael Czechowski Date: Sat, 28 Mar 2026 19:17:48 +0100 Subject: [PATCH 1/2] docs: add spec, plan, and tasks for flexbox task wording fix (#3) --- specs/003-flexbox-task-wording/plan.md | 76 +++++++++++++++++++++++++ specs/003-flexbox-task-wording/spec.md | 35 ++++++++++++ specs/003-flexbox-task-wording/tasks.md | 13 +++++ 3 files changed, 124 insertions(+) create mode 100644 specs/003-flexbox-task-wording/plan.md create mode 100644 specs/003-flexbox-task-wording/spec.md create mode 100644 specs/003-flexbox-task-wording/tasks.md diff --git a/specs/003-flexbox-task-wording/plan.md b/specs/003-flexbox-task-wording/plan.md new file mode 100644 index 0000000..1961245 --- /dev/null +++ b/specs/003-flexbox-task-wording/plan.md @@ -0,0 +1,76 @@ +# Implementation Plan + +## Objective + +Rewrite all 6 flexbox lesson task descriptions to describe the desired visual outcome instead of giving the exact CSS declaration. Update validation messages to hint without revealing answers, and accept alternative valid solutions where applicable. + +## Approach + +This is a content-only change to a single JSON file (`lessons/flexbox.json`). Each lesson needs three edits: + +1. **Task text**: Replace copy-pasteable CSS declarations with outcome-oriented descriptions +2. **Validation messages**: Replace answer-revealing messages with pedagogical hints +3. **Validations array**: Add alternative accepted solutions where multiple CSS approaches achieve the same visual result + +The lesson `description` fields (which teach concepts with code examples) remain unchanged — they are the learning material, not the exercise prompt. + +## File Mapping + +| File | Action | Description | +|------|--------|-------------| +| `lessons/flexbox.json` | modify | Rewrite `task` and validation `message` fields for all 6 lessons; add alternative validations for flexbox-6 | + +No new files need to be created. No validator code changes needed — the existing `property_value` and `regex` validation types already support everything required. + +## Detailed Changes Per Lesson + +### flexbox-1 (Container) +- **Task**: Describe that nav links stack vertically and should display side by side +- **Validation msg**: Hint at display property for flex layout +- **Alt solutions**: None — `display: flex` is the only correct answer (inline-flex changes block behavior) + +### flexbox-2 (Gap) +- **Task**: Describe that links are crammed together and need 1rem of spacing between them +- **Validation msg**: Hint at the gap property +- **Alt solutions**: None — `gap: 1rem` is the specific expected value + +### flexbox-3 (Justify Content) +- **Task**: Describe that Login button should be pushed to the far right, with nav links on the left +- **Validation msg**: Hint at main-axis distribution property +- **Alt solutions**: None — `justify-content: space-between` is the only property that works when targeting `.nav` + +### flexbox-4 (Align Items) +- **Task**: Describe the visual misalignment and ask for vertical centering +- **Validation msg**: Hint at cross-axis alignment property +- **Alt solutions**: None — `align-items: center` is the correct answer + +### flexbox-5 (Flex Wrap) +- **Task**: Describe cards overflowing and needing to flow onto new rows +- **Validation msg**: Hint at wrapping property +- **Alt solutions**: None — `flex-wrap: wrap` is the only answer + +### flexbox-6 (Flex Grow) +- **Task**: Describe that the search input should stretch to fill remaining space +- **Validation msg**: Hint at flex growth property +- **Alt solutions**: Accept both `flex: 1` and `flex-grow: 1` via regex validation + +## Architecture Decisions + +1. **No validator code changes**: The existing `regex` validation type can handle alternative solutions for flexbox-6. No need to add a new validation type. +2. **Keep values in tasks where needed**: Some tasks mention target values like "1rem" since the validator checks exact values and students need to know the amount. The key change is removing the *property name* from the task. +3. **Solution field unchanged**: The `solution` field is used for the "show solution" feature and should remain as the canonical answer. +4. **codePrefix unchanged**: The existing codePrefix already shows the selector context (e.g., `.nav {`), which is enough guidance for students. + +## Risks + +| Risk | Likelihood | Mitigation | +|------|-----------|------------| +| Tasks become too vague for beginners | Low | Descriptions still teach the property; tasks describe specific visual outcomes | +| Alternative regex validation too permissive | Low | Regex will be specific to `flex:\s*1` and `flex-grow:\s*1` patterns | +| Validation messages too cryptic | Low | Messages will hint at the property category without giving the exact declaration | + +## Testing Strategy + +1. **Run existing test suite**: `npm run test` — all tests should pass since no code or module structure changes +2. **Manual verification**: Validate that each rewritten task accurately describes the visual outcome shown in the preview +3. **JSON schema validation**: Ensure `lessons/flexbox.json` still conforms to the module schema diff --git a/specs/003-flexbox-task-wording/spec.md b/specs/003-flexbox-task-wording/spec.md new file mode 100644 index 0000000..148d746 --- /dev/null +++ b/specs/003-flexbox-task-wording/spec.md @@ -0,0 +1,35 @@ +# fix: remove answers from flexbox task descriptions (copy-paste score 95%) + +**Issue**: [public/code-crispies#3](https://git.librete.ch/public/code-crispies/issues/3) +**State**: open +**Author**: libretech +**Labels**: none +**Complexity**: simple + +## Issue Body + +Pedagogy audit: All 6 flexbox exercises give the exact CSS declaration in the task text. Students type without understanding. Rewrite tasks to describe the DESIRED OUTCOME instead of the exact code. Example: 'Add display: flex' → 'The navigation links stack vertically. Make them display side by side.' Accept multiple valid solutions in validations. + +## Current State + +All 6 lessons in `lessons/flexbox.json` have task descriptions that include the exact CSS declaration students need to type: + +| Lesson | Current Task (gives away answer) | +|--------|----------------------------------| +| flexbox-1 | "Add `display: flex` to `.nav`" | +| flexbox-2 | "Add `gap: 1rem` to space out..." | +| flexbox-3 | "setting `justify-content: space-between` on the nav" | +| flexbox-4 | "Center them vertically with `align-items: center`" | +| flexbox-5 | "Add `flex-wrap: wrap` to allow them to wrap" | +| flexbox-6 | "setting `flex: 1` on `.search`" | + +Validation error messages also give away answers (e.g., "Set `display: flex`"). + +## Acceptance Criteria + +1. All 6 flexbox task descriptions rewritten to describe the desired visual outcome, not the exact CSS code +2. Students cannot copy-paste from the task into the editor to pass +3. Validation error messages updated to provide hints without revealing the exact declaration +4. Where applicable, validations accept multiple valid CSS solutions (e.g., `flex: 1` and `flex-grow: 1`) +5. Existing tests continue to pass +6. Lesson descriptions (which teach the concepts) remain unchanged diff --git a/specs/003-flexbox-task-wording/tasks.md b/specs/003-flexbox-task-wording/tasks.md new file mode 100644 index 0000000..3229d9c --- /dev/null +++ b/specs/003-flexbox-task-wording/tasks.md @@ -0,0 +1,13 @@ +# Tasks + +## Phase 1: Core Content Changes +- [ ] Task 1.1: Rewrite task text for all 6 flexbox lessons to describe visual outcomes [P] +- [ ] Task 1.2: Rewrite validation error messages to hint without revealing answers [P] + +## Phase 2: Alternative Validations +- [ ] Task 2.1: Add regex validation for flexbox-6 to accept both `flex: 1` and `flex-grow: 1` + +## Phase 3: Validation +- [ ] Task 3.1: Run existing test suite to confirm no regressions +- [ ] Task 3.2: Verify flexbox.json still conforms to module schema +- [ ] Task 3.3: Run lesson format check (`npm run format.lessons`) From ad352aa986b440a95ace78a8f38a5895c8103897 Mon Sep 17 00:00:00 2001 From: Michael Czechowski Date: Sat, 28 Mar 2026 19:25:32 +0100 Subject: [PATCH 2/2] fix: rewrite flexbox task descriptions to describe outcomes instead of answers (#3) Replace copy-pasteable CSS declarations in all 6 flexbox lesson tasks with outcome-oriented descriptions. Update validation error messages to hint at properties without revealing exact declarations. Add regex validation for flexbox-6 to accept both flex: 1 and flex-grow: 1. --- lessons/flexbox.json | 28 ++++++++++++------------- specs/003-flexbox-task-wording/tasks.md | 12 +++++------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lessons/flexbox.json b/lessons/flexbox.json index 6646dd2..b8f31e7 100644 --- a/lessons/flexbox.json +++ b/lessons/flexbox.json @@ -9,7 +9,7 @@ "id": "flexbox-1", "title": "Container", "description": "Before flexbox, creating even simple layouts required floats, positioning hacks, or table-based layouts. Flexbox (Flexible Box Layout) revolutionized CSS by providing a one-dimensional layout system designed specifically for distributing space and aligning content.

How it works: When you set display: flex on an element, it becomes a flex container. Its direct children automatically become flex items that flow along a main axis (horizontal by default). This single property transforms stacked block elements into a horizontal row.

The two axes:
Main axis – The primary direction items flow (row = left→right)
Cross axis – Perpendicular to main (row = top→bottom)

.nav {\n  display: flex;\n}
", - "task": "This navigation menu stacks vertically. Add display: flex to .nav to arrange the links horizontally.", + "task": "The navigation links are stacking vertically. Make them display side by side in a horizontal row.", "previewHTML": "", "previewBaseCSS": "body { font-family: system-ui, sans-serif; margin: 0; } .nav { background: #1a1a2e; padding: 1rem; } .nav a { color: white; text-decoration: none; padding: 8px 1rem; border-radius: 4px; } .nav a:hover { background: rgba(255,255,255,0.1); }", "sandboxCSS": "", @@ -22,7 +22,7 @@ { "type": "property_value", "value": { "property": "display", "expected": "flex" }, - "message": "Set display: flex" + "message": "Try changing the display mode to create a flex container" } ] }, @@ -30,7 +30,7 @@ "id": "flexbox-2", "title": "Gap", "description": "The gap property adds consistent spacing between flex items without needing margins. It only creates space between items, not around the edges.", - "task": "Add gap: 1rem to space out the navigation links evenly.", + "task": "The navigation links are crammed together with no breathing room. Add 1rem of spacing between them.", "previewHTML": "", "previewBaseCSS": "body { font-family: system-ui, sans-serif; margin: 0; } .nav { background: #1a1a2e; padding: 1rem; display: flex; } .nav a { color: white; text-decoration: none; padding: 8px 1rem; border-radius: 4px; background: rgba(255,255,255,0.1); }", "sandboxCSS": "", @@ -43,7 +43,7 @@ { "type": "property_value", "value": { "property": "gap", "expected": "1rem" }, - "message": "Set gap: 1rem" + "message": "Use the property that adds spacing between flex items" } ] }, @@ -51,7 +51,7 @@ "id": "flexbox-3", "title": "Justify Content", "description": "justify-content distributes items along the main axis. Common values:
flex-start – pack items at the start
flex-end – pack at the end
center – center items
space-between – equal space between items
space-around – equal space around items", - "task": "Push the \"Login\" button to the right by setting justify-content: space-between on the nav.", + "task": "The Login button should sit on the far right, with the other links staying on the left. Distribute the space between them.", "previewHTML": "", "previewBaseCSS": "body { font-family: system-ui, sans-serif; margin: 0; } .nav { background: #1a1a2e; padding: 1rem; display: flex; } .links { display: flex; gap: 8px; } .nav a { color: white; text-decoration: none; padding: 8px 1rem; border-radius: 4px; } .nav a:hover { background: rgba(255,255,255,0.1); } .login { background: steelblue; }", "sandboxCSS": "", @@ -64,7 +64,7 @@ { "type": "property_value", "value": { "property": "justify-content", "expected": "space-between" }, - "message": "Set justify-content: space-between" + "message": "Use the property that distributes items along the main axis" } ] }, @@ -72,7 +72,7 @@ "id": "flexbox-4", "title": "Align Items", "description": "align-items controls alignment on the cross axis (vertical when flex-direction is row). Values include:
stretch – stretch to fill (default)
flex-start – align to top
flex-end – align to bottom
center – center vertically", - "task": "The logo and nav links have different heights. Center them vertically with align-items: center.", + "task": "The logo and nav links sit at different heights. Center them vertically so they line up.", "previewHTML": "
ACME
", "previewBaseCSS": "body { font-family: system-ui, sans-serif; margin: 0; } .header { background: white; padding: 1rem 2rem; display: flex; justify-content: space-between; border-bottom: 1px solid #eee; } .logo { font-size: 1.5rem; font-weight: bold; color: steelblue; } nav { display: flex; gap: 1rem; } nav a { color: #333; text-decoration: none; font-size: 0.9rem; }", "sandboxCSS": "", @@ -85,7 +85,7 @@ { "type": "property_value", "value": { "property": "align-items", "expected": "center" }, - "message": "Set align-items: center" + "message": "Use the property that controls cross-axis alignment" } ] }, @@ -93,7 +93,7 @@ "id": "flexbox-5", "title": "Flex Wrap", "description": "By default, flex items squeeze onto one line. flex-wrap: wrap allows items to flow onto multiple lines when they run out of space.", - "task": "These cards overflow the container. Add flex-wrap: wrap to allow them to wrap to new rows.", + "task": "The cards overflow the container instead of fitting within it. Allow the items to flow onto new rows when they run out of space.", "previewHTML": "
Card 1
Card 2
Card 3
Card 4
Card 5
Card 6
", "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; background: #f5f5f5; } .cards { display: flex; gap: 1rem; } .card { background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); min-width: 120px; text-align: center; }", "sandboxCSS": "", @@ -106,7 +106,7 @@ { "type": "property_value", "value": { "property": "flex-wrap", "expected": "wrap" }, - "message": "Set flex-wrap: wrap" + "message": "Use the property that allows flex items to wrap onto new lines" } ] }, @@ -114,7 +114,7 @@ "id": "flexbox-6", "title": "Flex Grow", "description": "The flex property on items controls how they grow and shrink. flex: 1 makes an item grow to fill available space. Multiple items with flex: 1 share space equally.", - "task": "Make the search input expand to fill available space by setting flex: 1 on .search.", + "task": "The search input is too narrow. Make it stretch to fill all the remaining space in the toolbar.", "previewHTML": "
", "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .toolbar { display: flex; gap: 8px; padding: 1rem; background: #f5f5f5; border-radius: 8px; } .search { padding: 8px 1rem; border: 1px solid #ddd; border-radius: 4px; font-size: 1rem; } .btn { padding: 8px 1rem; background: steelblue; color: white; border: none; border-radius: 4px; cursor: pointer; }", "sandboxCSS": "", @@ -125,9 +125,9 @@ "previewContainer": "preview-area", "validations": [ { - "type": "property_value", - "value": { "property": "flex", "expected": "1" }, - "message": "Set flex: 1" + "type": "regex", + "value": "(flex\\s*:\\s*1|flex-grow\\s*:\\s*1)", + "message": "Use the property that makes a flex item grow to fill available space" } ] } diff --git a/specs/003-flexbox-task-wording/tasks.md b/specs/003-flexbox-task-wording/tasks.md index 3229d9c..bf9999d 100644 --- a/specs/003-flexbox-task-wording/tasks.md +++ b/specs/003-flexbox-task-wording/tasks.md @@ -1,13 +1,13 @@ # Tasks ## Phase 1: Core Content Changes -- [ ] Task 1.1: Rewrite task text for all 6 flexbox lessons to describe visual outcomes [P] -- [ ] Task 1.2: Rewrite validation error messages to hint without revealing answers [P] +- [X] Task 1.1: Rewrite task text for all 6 flexbox lessons to describe visual outcomes [P] +- [X] Task 1.2: Rewrite validation error messages to hint without revealing answers [P] ## Phase 2: Alternative Validations -- [ ] Task 2.1: Add regex validation for flexbox-6 to accept both `flex: 1` and `flex-grow: 1` +- [X] Task 2.1: Add regex validation for flexbox-6 to accept both `flex: 1` and `flex-grow: 1` ## Phase 3: Validation -- [ ] Task 3.1: Run existing test suite to confirm no regressions -- [ ] Task 3.2: Verify flexbox.json still conforms to module schema -- [ ] Task 3.3: Run lesson format check (`npm run format.lessons`) +- [X] Task 3.1: Run existing test suite to confirm no regressions +- [X] Task 3.2: Verify flexbox.json still conforms to module schema +- [X] Task 3.3: Run lesson format check (`npm run format.lessons`)