Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 17 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ content repository for **Programmierung** (programming): a Git repository
of plain lesson files that the app loads directly and no vendor can lock
away.

It ships three German-language knowledge sets (domain `programming`,
`domain_label` Programmierung) in ascending difficulty: a Python
It ships three German-language knowledge sets (domain `programming`) in ascending difficulty: a Python
beginners course and a two-part React series. This repository was
created from
[adaptive-learner-content-template](https://github.com/astrapi69/adaptive-learner-content-template),
Expand All @@ -28,7 +27,7 @@ described below.
Drei Sets, 28 Lektionen, Quell- und Zielsprache Deutsch. Empfohlene
Reihenfolge:

### Teil 1 `sets/de/python-basics` (A1, 15 Lektionen)
### Teil 1: `sets/de/python-basics` (A1, 15 Lektionen)

Einführung in die Programmierung mit Python: von `print()` und Variablen
über Strings, Listen, Bedingungen und Schleifen bis zu Funktionen,
Expand All @@ -40,7 +39,7 @@ mit lauffähigen Code-Beispielen und erwarteter Ausgabe.
| 01 | `01-erste-schritte.json` | Erste Schritte mit Python |
| 02 | `02-variablen-und-datentypen.json` | Variablen und Datentypen |
| 03 | `03-zahlen-und-operatoren.json` | Zahlen und Operatoren |
| 04 | `04-strings.json` | Strings mit Text arbeiten |
| 04 | `04-strings.json` | Strings: mit Text arbeiten |
| 05 | `05-listen.json` | Listen (Lists) |
| 06 | `06-bedingungen.json` | Bedingungen (if / elif / else) |
| 07 | `07-schleifen.json` | Schleifen (for & while) |
Expand All @@ -53,7 +52,7 @@ mit lauffähigen Code-Beispielen und erwarteter Ausgabe.
| 14 | `14-comprehensions.json` | List Comprehensions |
| 15 | `15-wiederholung.json` | Wiederholung und Festigung |

### Teil 2 `sets/de/react-grundlagen` (A2, 5 Lektionen)
### Teil 2: `sets/de/react-grundlagen` (A2, 5 Lektionen)

| # | Lesson | Titel |
|---|--------|-------|
Expand All @@ -63,7 +62,7 @@ mit lauffähigen Code-Beispielen und erwarteter Ausgabe.
| 04 | `04-state-usestate.json` | State mit useState: Re-Render statt direkter Mutation |
| 05 | `05-events-und-grundprinzipien.json` | Events, Hooks & Grundprinzipien: Re-Render und Komposition |

### Teil 3 `sets/de/react-fortgeschritten` (B1, 8 Lektionen)
### Teil 3: `sets/de/react-fortgeschritten` (B1, 8 Lektionen)

| # | Lesson | Titel |
|---|--------|-------|
Expand All @@ -78,19 +77,19 @@ mit lauffähigen Code-Beispielen und erwarteter Ausgabe.

## What's inside

- `manifest.yaml` the root manifest listing the sets.
- `manifest.yaml`: the root manifest listing the sets.
- `sets/de/python-basics/`, `sets/de/react-grundlagen/`,
`sets/de/react-fortgeschritten/` the lesson sets.
- `schema/` the pinned [`learn-content-engine`](https://github.com/astrapi69/learn-content-engine)
`sets/de/react-fortgeschritten/`: the lesson sets.
- `schema/`: the pinned [`learn-content-engine`](https://github.com/astrapi69/learn-content-engine)
schema mirror; [`engine-version.txt`](schema/engine-version.txt) holds the
pinned engine version and is the source of truth. This is what the content
is validated against independent of the app.
- `templates/` starting-point lessons per domain (language / programming / knowledge).
- `scripts/validate_content.py` the local validator.
- `scripts/generate_exercises.py` an optional BYOK AI exercise generator.
- `generated/` staging area for AI drafts (never shipped directly).
- `.github/workflows/` CI that validates every push/PR against the pinned engine.
- `docs/` [GETTING-STARTED.md](docs/GETTING-STARTED.md) and a local
is validated against, independent of the app.
- `templates/`: starting-point lessons per domain (language / programming / knowledge).
- `scripts/validate_content.py`: the local validator.
- `scripts/generate_exercises.py`: an optional BYOK AI exercise generator.
- `generated/`: staging area for AI drafts (never shipped directly).
- `.github/workflows/`: CI that validates every push/PR against the pinned engine.
- `docs/`: [GETTING-STARTED.md](docs/GETTING-STARTED.md) and a local
[LESSON-FORMAT.md](docs/LESSON-FORMAT.md). The **canonical, test-validated**
format reference is the engine's
[`docs/lesson-format.md`](https://github.com/astrapi69/learn-content-engine/blob/main/docs/lesson-format.md).
Expand All @@ -116,15 +115,15 @@ and npm) and checks every lesson and manifest with the engine's rule ids
(`E-CARD-REF` & co.). `make lint-warnings` additionally prints the engine gate's warnings (`W-*`).

No `make` (e.g. Windows without WSL)? Two options: run the validator in a
virtualenv yourself
virtualenv yourself:

```bash
python3 -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
python3 scripts/validate_content.py
```

— or just commit and let the GitHub Actions CI validate (it runs the same
Or just commit and let the GitHub Actions CI validate (it runs the same
checks). Installing the deps globally with a bare `pip install` fails on
modern Debian/Ubuntu/macOS (PEP 668, "externally-managed-environment");
the virtualenv above is why.
Expand Down
6 changes: 3 additions & 3 deletions docs/GETTING-STARTED.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Getting started your first lesson in 10 minutes
# Getting started: your first lesson in 10 minutes

This walkthrough takes you from zero to a validated lesson. You'll copy a
template, edit it, register it, and run the validator.
Expand All @@ -18,12 +18,12 @@ You need:
> No `make` (e.g. Windows without WSL)? Either create a virtualenv
> yourself (`python3 -m venv .venv`, activate it,
> `pip install -r requirements.txt`), or skip local validation and let the
> GitHub Actions CI check your commit it runs the same validator. A bare
> GitHub Actions CI check your commit: it runs the same validator. A bare
> `pip install` fails on modern systems (PEP 668).

### Start your own content repository

Create your repository from this template **“Use this template” → Create
Create your repository from this template: **“Use this template” → Create
a new repository** (not *Fork*), then clone your new repo:

> <https://github.com/astrapi69/adaptive-learner-content-template> → **Use
Expand Down
10 changes: 5 additions & 5 deletions docs/LESSON-FORMAT.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Lesson format local summary
# Lesson format: local summary

> **The canonical, test-validated format reference is the engine's**
> **[`docs/lesson-format.md`](https://github.com/astrapi69/learn-content-engine/blob/main/docs/lesson-format.md)**
Expand All @@ -13,7 +13,7 @@ This is a field-by-field summary of the lesson format used by this repository.
Lessons that follow it pass `scripts/validate_content.py` and load in the
Adaptive Learner app.

The lesson format is **one JSON file per lesson** this is what the app loads
The lesson format is **one JSON file per lesson**: this is what the app loads
and the validator checks. It is summarised below.

New to this? Start with [GETTING-STARTED.md](GETTING-STARTED.md) and copy a
Expand All @@ -32,7 +32,7 @@ manifest.yaml # root: lists every set
```

- **Language sets** live at `sets/<source>/<target>-<level>/`
(e.g. `sets/en/es-a1/` Spanish for English speakers, level A1).
(e.g. `sets/en/es-a1/`: Spanish for English speakers, level A1).
- **Non-language sets** (e.g. psychology, programming) use a topic folder name
(e.g. `sets/de/psych-intro/`), because material and explanation share one
language.
Expand Down Expand Up @@ -123,8 +123,8 @@ The inner `exercise` object's `type` picks one of the six exercise types below.
Most carry `card_ids` (the cards they draw on) and a `direction`.

**`direction`** (productive vs receptive):
- `source_to_target` learner produces the target language (harder).
- `target_to_source` learner recognises/translates into the source (easier).
- `source_to_target`: learner produces the target language (harder).
- `target_to_source`: learner recognises/translates into the source (easier).

## The six exercise types

Expand Down
4 changes: 2 additions & 2 deletions generated/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# generated/ Staging-Bereich für KI-Entwürfe
# generated/: Staging-Bereich für KI-Entwürfe

`scripts/generate_exercises.py` schreibt jede generierte Lektion HIERHER,
niemals direkt in einen ausgelieferten `sets/`-Baum. Das ist die
Expand All @@ -11,7 +11,7 @@ Ablauf:
`generated/<set-id>/<lektion>.json` an (nur nachdem der Entwurf den
Struktur- + Qualitäts-Gate von `validate_content.py` bestanden hat).
2. Sichten: Lies die Lektion. Für eine Sprache, die du nicht muttersprachlich
sprichst, hol ein Muttersprachler-Review ein kein Validator erkennt
sprichst, hol ein Muttersprachler-Review ein: kein Validator erkennt
eine unnatürliche Formulierung oder eine falsche Umschrift.
3. Einsortieren: Verschiebe die Datei in dein Set unter
`sets/<quellsprache>/<set-id>/lessons/`, trage sie im Set-Manifest ein
Expand Down
16 changes: 8 additions & 8 deletions schema/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Schema (mirror do not edit here)
# Schema (mirror, do not edit here)

**Mirror of the `learn-content-engine` `schema/`**, pinned to the version in
[`engine-version.txt`](engine-version.txt) (source of truth chain:
Expand All @@ -19,17 +19,17 @@ together in one deliberate PR, so the pinned version lives in exactly one place
|------|-----------------------------|------------------|
| `lesson.schema.json` | `package/schema/lesson.schema.json` | `scripts/validate_content.py` (structural validation via `jsonschema`), `tests/test_shape_parity.py` |
| `content-manifest.schema.json` | `package/schema/content-manifest.schema.json` | vendored for IDE autocomplete / third-party manifest validation; CI validates manifests with the engine itself (`engine-validate.yml`) |
| `quality-rules.json` | `package/schema/quality-rules.json` (engine ≥ 0.4.0 locally owned before that) | `scripts/validate_content.py` (quality minimums: `minExercisesPerLesson`, `minExerciseTypes`, `minFreeTextAccepts`, `minMatchingPairs`, `minTheorySteps`) |
| `engine-version.txt` | (the pin itself) | `scripts/check_schema_drift.py`, `.github/workflows/engine-validate.yml` |
| `quality-rules.json` | `package/schema/quality-rules.json` (engine ≥ 0.4.0, locally owned before that) | `scripts/validate_content.py` (quality minimums: `minExercisesPerLesson`, `minExerciseTypes`, `minFreeTextAccepts`, `minMatchingPairs`, `minTheorySteps`) |
| `engine-version.txt` | - (the pin itself) | `scripts/check_schema_drift.py`, `.github/workflows/engine-validate.yml` |

`lesson.schema.json` is a self-contained JSON Schema (Draft 2020-12) — its
`lesson.schema.json` is a self-contained JSON Schema (Draft 2020-12). Its
`$id`, `$schema` and `x-schema-version` make it usable for IDE autocomplete
(reference it from a lesson `.json` via `"$schema"`) and for `jsonschema`/`ajv`
validation.

## Locally owned (NOT part of the engine mirror)

* `../tests/fixtures/lesson-shape-parity.json` the shape-parity fixture
* `../tests/fixtures/lesson-shape-parity.json`: the shape-parity fixture
snapshot (see `tests/test_shape_parity.py`). The cross-repo parity
guarantee is closed by the app's own app-vs-engine parity test plus this
repo's engine-pinned drift gate, so the fixture no longer needs to be
Expand All @@ -40,12 +40,12 @@ validation.
`scripts/check_schema_drift.py` (run in CI by
`.github/workflows/schema-drift.yml`) downloads the **npm tarball of the
pinned engine release** at CI time and compares it byte-for-byte against
this mirror. The npm tarball not a git tag is the comparison source
this mirror. The npm tarball (not a git tag) is the comparison source
because a published npm version is immutable (the registry refuses
re-publishing a version, git tags can be moved or deleted), it is exactly
the artefact validator consumers install via
`npm ci learn-content-engine@<pin>`, and it needs a single anonymous HTTPS
GET no GitHub token, still Python-stdlib-only.
GET: no GitHub token, still Python-stdlib-only.

The mirror stays **vendored** so validation works offline: only the drift
CHECK itself needs network.
Expand All @@ -65,6 +65,6 @@ after an accidental hand-edit).

`.github/workflows/engine-validate.yml` additionally runs the engine's own
`validateLesson()` / `validateManifest()` (at the pinned version) over the
whole repo content the semantic rules (cloze blanks == markers,
whole repo content: the semantic rules (cloze blanks == markers,
referential integrity, multiselect disjointness, picture exactly-one-correct)
that a JSON Schema cannot express. Gate: zero errors.
6 changes: 3 additions & 3 deletions templates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Copy-and-edit starting points for new lessons, one per content **domain**.

A lesson is a **single JSON file** that is the lesson format. Pick the
A lesson is a **single JSON file**: that is the lesson format. Pick the
template for your domain and copy it.

| Template | Domain | Use it for |
Expand All @@ -19,7 +19,7 @@ template for your domain and copy it.
3. **Replace** the placeholder cards, theory and exercises with your content.
4. **Register** the file in your set's `manifest.yaml` (`metadata.lessons`) and
make sure the set is listed in the root `manifest.yaml`.
5. **Validate**: `python scripts/validate_content.py` it must print
5. **Validate**: `python scripts/validate_content.py`, it must print
`All N set(s) passed validation.`

> JSON has no comments, so the field-by-field explanations live in
Expand All @@ -35,7 +35,7 @@ with distractors. Keep those minimums when you edit.
## Domain differences at a glance

- **language**: `domain: language`, `target_language` **and** `source_language`
differ, `level` is a CEFR band (A1C2). Matching/free-text use a
differ, `level` is a CEFR band (A1-C2). Matching/free-text use a
translation context (target ↔ source).
- **knowledge**: `domain: psychology` (or another non-language domain),
`source_language == target_language`, no separate target. Matching/free-text
Expand Down