@lernapps/tooling 0.0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +67 -2
  3. package/archetypes/shared/a11y.ts +38 -0
  4. package/archetypes/shared/hooks/pre-commit +22 -0
  5. package/archetypes/shared/hooks/pre-push +4 -0
  6. package/archetypes/shared/i18n.ts +25 -0
  7. package/archetypes/shared/install-hooks.ts +63 -0
  8. package/archetypes/shared/playwright.ts +54 -0
  9. package/archetypes/shared/preset.ts +81 -0
  10. package/archetypes/shared/storage.ts +167 -0
  11. package/archetypes/shared/tsconfig.json +27 -0
  12. package/check/validation-report.v1.schema.json +116 -0
  13. package/dist/a11y.mjs +30 -0
  14. package/dist/check/rules/accessible.mjs +18 -0
  15. package/dist/check/rules/app-content-guide.mjs +69 -0
  16. package/dist/check/rules/dependency-licence.mjs +82 -0
  17. package/dist/check/rules/entry-fitness-matches.mjs +22 -0
  18. package/dist/check/rules/entry-links-resolve.mjs +44 -0
  19. package/dist/check/rules/explainer-readable-without-js.mjs +66 -0
  20. package/dist/check/rules/links-resolve.mjs +10 -0
  21. package/dist/check/rules/lockfile-matches.mjs +57 -0
  22. package/dist/check/rules/no-request-before-click.mjs +17 -0
  23. package/dist/check/rules/no-tracking.mjs +17 -0
  24. package/dist/check/rules/own-data-only.mjs +66 -0
  25. package/dist/check/rules/pages-reachable.mjs +25 -0
  26. package/dist/check/rules/usable-at-360px.mjs +19 -0
  27. package/dist/check-cv4I6CCH.mjs +28 -0
  28. package/dist/cli.mjs +3118 -0
  29. package/dist/i18n.mjs +11 -0
  30. package/dist/lint.mjs +528 -0
  31. package/dist/plan-DWKayEnY.mjs +75 -0
  32. package/dist/playwright.mjs +47 -0
  33. package/dist/preset.mjs +60 -0
  34. package/dist/skills/lernapps-app/SKILL.md +49 -0
  35. package/dist/skills/lernapps-cli/SKILL.md +156 -0
  36. package/dist/skills/lernapps-cli/references/platform-rules.md +258 -0
  37. package/dist/skills/lernapps-commit/SKILL.md +39 -0
  38. package/dist/skills/lernapps-content-growth/SKILL.md +33 -0
  39. package/dist/skills/lernapps-content-questions/SKILL.md +133 -0
  40. package/dist/skills/lernapps-content-questions/references/question-types.md +69 -0
  41. package/dist/skills/lernapps-content-research/SKILL.md +50 -0
  42. package/dist/skills/lernapps-content-research/references/sources.md +16 -0
  43. package/dist/skills/lernapps-exercise-patterns/SKILL.md +74 -0
  44. package/dist/skills/lernapps-exercise-patterns/references/biology-geography.md +13 -0
  45. package/dist/skills/lernapps-exercise-patterns/references/chemistry.md +16 -0
  46. package/dist/skills/lernapps-exercise-patterns/references/computer-science.md +13 -0
  47. package/dist/skills/lernapps-exercise-patterns/references/figures.md +10 -0
  48. package/dist/skills/lernapps-exercise-patterns/references/history.md +13 -0
  49. package/dist/skills/lernapps-exercise-patterns/references/mathematics.md +19 -0
  50. package/dist/skills/lernapps-exercise-patterns/references/page-structures.md +8 -0
  51. package/dist/skills/lernapps-exercise-patterns/references/physics.md +18 -0
  52. package/dist/skills/lernapps-exercise-patterns/references/success.md +28 -0
  53. package/dist/skills/lernapps-explainer/SKILL.md +33 -0
  54. package/dist/skills/lernapps-explainer/references/blocks.md +83 -0
  55. package/dist/skills/lernapps-explainer/references/components.md +66 -0
  56. package/dist/skills/lernapps-explainer/references/exercises.md +115 -0
  57. package/dist/skills/lernapps-explainer/references/rules.md +285 -0
  58. package/dist/skills/lernapps-explainer/references/runtime.md +79 -0
  59. package/dist/skills/lernapps-explainer/references/structure.md +24 -0
  60. package/dist/skills/lernapps-explainer-design/SKILL.md +57 -0
  61. package/dist/skills/lernapps-explainer-design/references/rules.md +75 -0
  62. package/dist/skills/lernapps-explainer-self-assessment/SKILL.md +93 -0
  63. package/dist/skills/lernapps-github/SKILL.md +102 -0
  64. package/dist/skills/lernapps-interactive/SKILL.md +141 -0
  65. package/dist/skills/lernapps-interactive/references/frame.md +30 -0
  66. package/dist/skills/lernapps-interactive-design/SKILL.md +58 -0
  67. package/dist/skills/lernapps-listing/SKILL.md +44 -0
  68. package/dist/skills/lernapps-listing/references/keeping-updated.md +33 -0
  69. package/dist/skills/lernapps-quiz/SKILL.md +100 -0
  70. package/dist/skills/lernapps-quiz-design/SKILL.md +48 -0
  71. package/dist/status-CXoQBgfU.mjs +76 -0
  72. package/dist/storage.mjs +113 -0
  73. package/generator/app/.agents/skills/app-content/SKILL.md +63 -0
  74. package/generator/app/.github/ISSUE_TEMPLATE/inhaltsfehler.yml +25 -0
  75. package/generator/app/.github/workflows/pages.yml +61 -0
  76. package/generator/app/LICENSE +21 -0
  77. package/generator/app/renovate.json +4 -0
  78. package/generator/architecture.ts +212 -0
  79. package/generator/create.ts +462 -0
  80. package/generator/init.ts +186 -0
  81. package/generator/update.ts +429 -0
  82. package/guidance/AGENTS.md +26 -0
  83. package/guidance/increment-template.md +194 -0
  84. package/guidance/plan-front-matter.v1.schema.json +36 -0
  85. package/guidance/plan-template.md +233 -0
  86. package/guidance/subagent-brief.md +25 -0
  87. package/guidance/workflow-rules.md +109 -0
  88. package/package.json +133 -4
  89. package/review/verdict.v1.schema.json +134 -0
  90. package/skills/archetypes/lernapps-explainer/SKILL.md +33 -0
  91. package/skills/archetypes/lernapps-explainer/references/blocks.md +83 -0
  92. package/skills/archetypes/lernapps-explainer/references/components.md +66 -0
  93. package/skills/archetypes/lernapps-explainer/references/exercises.md +115 -0
  94. package/skills/archetypes/lernapps-explainer/references/rules.md +285 -0
  95. package/skills/archetypes/lernapps-explainer/references/runtime.md +79 -0
  96. package/skills/archetypes/lernapps-explainer/references/structure.md +24 -0
  97. package/skills/archetypes/lernapps-explainer-design/SKILL.md +57 -0
  98. package/skills/archetypes/lernapps-explainer-design/references/rules.md +75 -0
  99. package/skills/archetypes/lernapps-explainer-self-assessment/SKILL.md +93 -0
  100. package/skills/archetypes/lernapps-interactive/SKILL.md +141 -0
  101. package/skills/archetypes/lernapps-interactive/references/frame.md +30 -0
  102. package/skills/archetypes/lernapps-interactive-design/SKILL.md +58 -0
  103. package/skills/archetypes/lernapps-quiz/SKILL.md +100 -0
  104. package/skills/archetypes/lernapps-quiz-design/SKILL.md +48 -0
  105. package/skills/content/lernapps-content-questions/SKILL.md +133 -0
  106. package/skills/content/lernapps-content-questions/references/question-types.md +69 -0
  107. package/skills/content/lernapps-content-research/SKILL.md +50 -0
  108. package/skills/content/lernapps-content-research/references/sources.md +16 -0
  109. package/skills/content/lernapps-exercise-patterns/SKILL.md +74 -0
  110. package/skills/content/lernapps-exercise-patterns/references/biology-geography.md +13 -0
  111. package/skills/content/lernapps-exercise-patterns/references/chemistry.md +16 -0
  112. package/skills/content/lernapps-exercise-patterns/references/computer-science.md +13 -0
  113. package/skills/content/lernapps-exercise-patterns/references/figures.md +10 -0
  114. package/skills/content/lernapps-exercise-patterns/references/history.md +13 -0
  115. package/skills/content/lernapps-exercise-patterns/references/mathematics.md +19 -0
  116. package/skills/content/lernapps-exercise-patterns/references/page-structures.md +8 -0
  117. package/skills/content/lernapps-exercise-patterns/references/physics.md +18 -0
  118. package/skills/content/lernapps-exercise-patterns/references/success.md +28 -0
  119. package/skills/process/lernapps-app/SKILL.md +49 -0
  120. package/skills/process/lernapps-commit/SKILL.md +39 -0
  121. package/skills/process/lernapps-content-growth/SKILL.md +33 -0
  122. package/skills/process/lernapps-github/SKILL.md +102 -0
  123. package/skills/process/lernapps-listing/SKILL.md +44 -0
  124. package/skills/process/lernapps-listing/references/keeping-updated.md +33 -0
  125. package/skills/tooling/lernapps-cli/SKILL.md +156 -0
  126. package/skills/tooling/lernapps-cli/references/platform-rules.md +258 -0
@@ -0,0 +1,156 @@
1
+ ---
2
+ name: lernapps-cli
3
+ description: Use in Code of a lernapps.net app - to create or update the app with the CLI, whenever a check, a git hook or a runtime test fails, and before you change the preset, the configuration or the storage. What `lernapps create`, `update`, `check` and `screenshots` do, how to fix from a message, when to suppress, and what of the preset you never change.
4
+ license: MIT
5
+ ---
6
+
7
+ # lernapps CLI and checks
8
+
9
+ ## Read when
10
+
11
+ - [references/platform-rules.md](references/platform-rules.md): a check names a `listing` rule, and before the
12
+ listing.
13
+
14
+ ## Create
15
+
16
+ 1. Only after the creator's yes to the plan (`explore-before-code`). In the plan's folder:
17
+ `npx lernapps create --archetype <archetype>`.
18
+ 2. No git repo yet: `git init --initial-branch=work`. Then `npm install` (dependencies, git hooks), and commit
19
+ everything on `work`.
20
+ 3. Needs git, Node ≥ 22.18, registry.npmjs.org. Blocked → ask the creator to allow it, run again. Never write the
21
+ app by hand.
22
+ 4. It keeps the plan and the installed skills, and writes the content guide's skeleton.
23
+
24
+ ## Update
25
+
26
+ - `npx --yes @lernapps/tooling@latest update`, then `npm install`: moves the app to this
27
+ tooling's runtime and checks, replaces the `lernapps-*` skills, adds what an older app lacks.
28
+ - `npm update` moves tooling and runtime only within their ranges (`^0.1.0` takes patches); `update` moves the ranges.
29
+
30
+ ## Check
31
+
32
+ - `npx lernapps check`: format, lint, types, unit tests, build, checks of the built app, end-to-end tests. The hooks
33
+ run its parts (`--pre-commit`, `--pre-push`); CI runs it whole.
34
+ - Report: `node_modules/.cache/lernapps/validation-report.yaml`. Options: `npx lernapps check --help`.
35
+
36
+ ## Look at the app
37
+
38
+ A check says the rules hold; only a look says what a learner sees. Show the creator the pages before a push, and before
39
+ a submission they declare something about.
40
+
41
+ - Explainer or quiz: build (`npx vp build`), then `npx lernapps screenshots`. It writes one image of every page, one of
42
+ every figure, and an `index.html` that shows them in order to `screenshots/` (not part of the app: do not commit it).
43
+ Show the images, or the `index.html` where you can show HTML. Check every figure in its own image
44
+ (`…-figure-<n>.png`): a page image is scaled down, its details are not readable. `--desktop` adds 1280 px images.
45
+ Options: `npx lernapps screenshots --help`.
46
+ - Interactive app: `screenshots` does not support it. Open the built app with the Playwright the tooling installs
47
+ (`import { chromium } from "playwright"`), at 390 px width, and take `page.screenshot({ fullPage: true })` of each
48
+ state the creator should see, from a short script outside the app.
49
+
50
+ ## A check fails
51
+
52
+ 1. Read the message: it names the step and links the rule (`https://lernapps.net/tooling/rules/#<id>`).
53
+ 2. Failed commit: one line names the step and `node_modules/.cache/lernapps/pre-commit.log`. Read that log.
54
+ 3. Fix the cause. The rule's text is in the skill of the phase; the link says where.
55
+ 4. Run the check again. Go on only when it passes.
56
+
57
+ - A runtime test (`@lernapps/app-templates`) fails while your content validates: a bug of the template.
58
+ 1. Tell the creator. Open an issue at <https://github.com/lernapps/app-templates/issues> with the validation
59
+ report, or ask the creator to.
60
+ 2. Never change tests, config or `node_modules` to get around it. Go on with the content.
61
+ 3. After the fix: update, check, commit.
62
+ - A link answers HTTP 429: "not checked", a hint that fails nothing. Tell the creator which; go on.
63
+
64
+ ## Rules
65
+
66
+ ### `checks-pass`: Run the checks before you push
67
+
68
+ ```rule
69
+ id: checks-pass
70
+ scope: tooling
71
+ severity: error
72
+ ```
73
+
74
+ - `lernapps check` passes before every push. The hooks run it too; CI runs the same command and keeps its report as
75
+ the artifact `validation-report`.
76
+
77
+ ### `fix-from-message`: Fix failed checks, never bypass them
78
+
79
+ ```rule
80
+ id: fix-from-message
81
+ scope: tooling
82
+ severity: error
83
+ ```
84
+
85
+ - Fix the cause the message names.
86
+ - Never bypass a hook: no `--no-verify`, no acceptance such as `ARC42_CONSISTENT` without a finding shown.
87
+ - Never delete a test to make it pass.
88
+
89
+ ### `suppression-reason`: Suppress only in place, with the reason
90
+
91
+ ```rule
92
+ id: suppression-reason
93
+ scope: tooling
94
+ severity: error
95
+ ```
96
+
97
+ - Lint: only on the line, with the rule named and the reason after `--`:
98
+ `// oxlint-disable-next-line lernapps/no-request-before-click -- the video loads after a click`.
99
+ - Types: only `// @ts-expect-error -- <reason>`; never `@ts-ignore` or `@ts-nocheck`.
100
+ - The review reads every suppression.
101
+
102
+ ### `lockfile-matches`: Commit the lock file with every dependency change
103
+
104
+ ```rule
105
+ id: lockfile-matches
106
+ scope: tooling
107
+ severity: error
108
+ ```
109
+
110
+ - Change dependencies with `npm install`, never in `package.json` alone; commit `package-lock.json` with it.
111
+ - A git pin (`github:…#<commit>`) moves in both files together.
112
+
113
+ ### `keep-the-preset`: Extend the preset, change nothing of it
114
+
115
+ ```rule
116
+ id: keep-the-preset
117
+ scope: [archetype:explainer, archetype:interactive, archetype:quiz]
118
+ severity: error
119
+ ```
120
+
121
+ - `vite.config.ts` is `export default lernapps()`, with only the app's own settings as generated
122
+ (`lernapps({ plugins: [quiz()] })`).
123
+ - `tsconfig.json` extends `@lernapps/tooling/tsconfig.json` as generated.
124
+ - The hooks come from the package (`prepare` in `package.json`); never replace one.
125
+ - Never turn a lint rule off or lower its severity.
126
+
127
+ ### `strict-typescript`: TypeScript only, strict
128
+
129
+ ```rule
130
+ id: strict-typescript
131
+ scope: [archetype:explainer, archetype:interactive, archetype:quiz]
132
+ severity: error
133
+ ```
134
+
135
+ - Every source file is TypeScript; no JavaScript files.
136
+ - Never `any`: use `unknown` and narrow it, or write the type.
137
+ - Type the creator's data; validate it at build time.
138
+
139
+ ### `storage-through-wrapper`: Store only through the preset's storage
140
+
141
+ ```rule
142
+ id: storage-through-wrapper
143
+ scope: [archetype:explainer, archetype:interactive, archetype:quiz]
144
+ severity: error
145
+ ```
146
+
147
+ - Only `createStorage` from `@lernapps/tooling/storage`, named after the app's id in the catalog (own prefix
148
+ `lernapps:<id>:`, rule `own-data-only`; works when storage is blocked).
149
+ - At most 100 kB under the prefix (keys and values, 2 bytes per UTF-16 unit). Beyond, `save` returns false and the
150
+ app keeps working.
151
+ - A setting of the learner that holds for every app or every app of the archetype: `createSettings("<id>",
152
+ "<archetype>")`, saved only where the learner chose it (`"app"`, `"archetype"` or `"all"`); the app's own goes first.
153
+ - Keep the learning state, not growing histories.
154
+ - What only a reload must not lose, such as an answer being written, lasts while the tab is open:
155
+ `createStorage("<id>", { type: "sessionStorage" })` (sessionStorage, same prefix and limit).
156
+ - Never `localStorage`, `sessionStorage`, IndexedDB or cookies directly.
@@ -0,0 +1,258 @@
1
+ # Platform rules
2
+
3
+ - Every app on lernapps.net, however built (this tooling, by hand, another framework, Lovable, bolt.new).
4
+ - Scope `listing`: every listed app, wherever hosted. Severity `error` never break; `hint` advice.
5
+ - Check a built or published app: `npx --yes @lernapps/tooling check <dir|url>` (= `lernapps check`);
6
+ `--entry <file>` checks the catalog entry against it.
7
+ - Published at its own address (e.g. `https://<owner>.github.io/<repo>/`); once listed, lernapps.net serves a copy at
8
+ `https://lernapps.net/apps/start/<id>/`, built from the entry's `commit`.
9
+ - All rules: <https://lernapps.net/tooling/rules/>.
10
+
11
+ ## App
12
+
13
+ ### `no-tracking`: Collect nothing, set no cookies
14
+
15
+ ```rule
16
+ id: no-tracking
17
+ scope: listing
18
+ severity: error
19
+ ```
20
+
21
+ - No cookies, analytics, tracking pixels, server storing data.
22
+ - Stored data stays on the device (`localStorage`, or `sessionStorage` while the tab is open) and serves only the app.
23
+
24
+ ### `own-data-only`: Touch only the app's own data in the browser
25
+
26
+ ```rule
27
+ id: own-data-only
28
+ scope: listing
29
+ severity: error
30
+ ```
31
+
32
+ - Every app on lernapps.net shares one origin with the other apps and the platform.
33
+ - Own data: keys of `localStorage` and `sessionStorage`, IndexedDB databases and caches named `lernapps:<id>:…`,
34
+ `<id>` the app's id in the catalog (`entries/<id>.yaml`).
35
+ - Also every app's: the learner's settings for every app (`lernapps:settings:<key>`, a key without a colon) and for
36
+ every app of the page's archetype (`lernapps:settings:<archetype>:…`, the archetype of
37
+ `<meta name="lernapps-archetype">`); never another archetype's. `settings` is never an app's id.
38
+ - Never read, write or remove other keys; never `clear()`; never `caches.match()` without `cacheName`.
39
+ - Built with this tooling: `createStorage("<id>")` from `@lernapps/tooling/storage`; settings with
40
+ `createSettings("<id>", "<archetype>")`.
41
+ - `lernapps check` puts another app's data into the browser and reports every access to it, before a click.
42
+
43
+ ### `runs-in-browser`: Runs in the browser, without installation
44
+
45
+ ```rule
46
+ id: runs-in-browser
47
+ scope: listing
48
+ severity: error
49
+ ```
50
+
51
+ - Opens and works at its URL in a current browser. No app store, download or extension.
52
+
53
+ ### `app-checkable`: The published app can be opened and checked
54
+
55
+ ```rule
56
+ id: app-checkable
57
+ scope: listing
58
+ severity: error
59
+ ```
60
+
61
+ - Opens at the entry's `url`; a built app from its bundle (`index.html`).
62
+ - Page does not load, build fails, no browser, check stops → only this rule is reported. Fix, check again.
63
+ - Opens in a browser but the check fails → issue at <https://github.com/lernapps/tooling/issues> with the message.
64
+
65
+ ### `no-account`: No account
66
+
67
+ ```rule
68
+ id: no-account
69
+ scope: listing
70
+ severity: error
71
+ ```
72
+
73
+ - Whole app usable without sign-up or login.
74
+
75
+ ### `free-of-charge`: Free of charge
76
+
77
+ ```rule
78
+ id: free-of-charge
79
+ scope: listing
80
+ severity: error
81
+ ```
82
+
83
+ - Every part free: no payment, paid upgrade or ending trial.
84
+
85
+ ### `no-ads`: No ads
86
+
87
+ ```rule
88
+ id: no-ads
89
+ scope: listing
90
+ severity: error
91
+ ```
92
+
93
+ - No advertising, sponsored content or product placement.
94
+
95
+ ### `learners-act`: Learners do something themselves
96
+
97
+ ```rule
98
+ id: learners-act
99
+ scope: listing
100
+ severity: error
101
+ ```
102
+
103
+ - Every page or screen asks learners to try, practise or decide. Reading alone is not enough.
104
+
105
+ ### `no-request-before-click`: No request to another server before a click
106
+
107
+ ```rule
108
+ id: no-request-before-click
109
+ scope: listing
110
+ severity: error
111
+ ```
112
+
113
+ - Bundle fonts, scripts, pictures at build time.
114
+ - Other servers (video, map) only after the learner's click.
115
+ - No other servers' URLs in code; at a click-to-load line suppress the lint message with this reason.
116
+
117
+ ### `accessible`: Accessible to WCAG 2.1 AA
118
+
119
+ ```rule
120
+ id: accessible
121
+ scope: listing
122
+ severity: error
123
+ ```
124
+
125
+ - WCAG 2.1 AA: labels, contrast, keyboard, text alternatives.
126
+ - Deviate only where the idea needs it (typing game against the clock); then say what is missing, in plain German,
127
+ in the entry's `limits`.
128
+ - With `limits`: `lernapps check --entry` reports warnings; without: errors.
129
+
130
+ ### `usable-at-360px`: Usable at 360 px
131
+
132
+ ```rule
133
+ id: usable-at-360px
134
+ scope: listing
135
+ severity: error
136
+ ```
137
+
138
+ - Every page at 360 px width: no horizontal scrolling, every control reachable.
139
+ - Deviate only where the idea needs it (keyboard required), in `limits` as under `accessible`.
140
+
141
+ ### `learner-text-german`: German always, every declared language complete
142
+
143
+ ```rule
144
+ id: learner-text-german
145
+ scope: listing
146
+ severity: error
147
+ ```
148
+
149
+ - Texts for learners, teachers, parents: German, plain (short sentences, active voice, no jargon).
150
+ - More languages only where the archetype supports them (explainer, quiz: `languages`, German first); each declared
151
+ language complete, no other.
152
+ - Texts out of code: in the content (explainer YAML, quiz bank) or message files (`src/messages/de.json`, shown
153
+ with `translator` from `@lernapps/tooling/i18n`).
154
+
155
+ ### `third-party-licence`: Name source and licence of others' content
156
+
157
+ ```rule
158
+ id: third-party-licence
159
+ scope: listing
160
+ severity: error
161
+ ```
162
+
163
+ - Others' content (texts, pictures, quotes) only with a licence that allows it; source and licence next to it.
164
+
165
+ ### `dependency-licence`: Only dependencies with an open licence
166
+
167
+ ```rule
168
+ id: dependency-licence
169
+ scope: listing
170
+ severity: error
171
+ ```
172
+
173
+ - `dependencies` only with these licences, transitively: MIT, MIT-0, ISC, 0BSD, BSD-2-Clause, BSD-3-Clause,
174
+ Apache-2.0, MPL-2.0, BlueOak-1.0.0, Zlib, Unlicense, CC0-1.0, CC-BY-4.0, Python-2.0.
175
+ - Build tools: `devDependencies`.
176
+
177
+ ### `links-resolve`: Every link resolves
178
+
179
+ ```rule
180
+ id: links-resolve
181
+ scope: listing
182
+ severity: error
183
+ ```
184
+
185
+ - Every link and resource points to a page or file the build writes. Relative links inside the app.
186
+
187
+ ### `pages-reachable`: Every page is reachable from the start page
188
+
189
+ ```rule
190
+ id: pages-reachable
191
+ scope: listing
192
+ severity: error
193
+ ```
194
+
195
+ - Every built page linked from the start page or a page it leads to; the listing checks only those.
196
+ - Pages nobody should reach: out of the build. Reached otherwise on purpose: `<meta name="robots" content="noindex">`.
197
+ - `404.html` at the root needs no link.
198
+ - On a URL the checks visit at most 100 pages (hint); check the bundle for all.
199
+
200
+ ### `no-learner-data-in-texts`: Nothing about a particular learner in public texts
201
+
202
+ ```rule
203
+ id: no-learner-data-in-texts
204
+ scope: listing
205
+ severity: error
206
+ ```
207
+
208
+ - No name, class, school, grade, picture or other detail of a real learner in app, entry, README, plan or commit
209
+ message, even if the creator mentions one. Made-up names in exercises.
210
+
211
+ ### `correct-content-support`: Help keep the content correct
212
+
213
+ ```rule
214
+ id: correct-content-support
215
+ scope: listing
216
+ severity: hint
217
+ ```
218
+
219
+ - Computable answers: generate exercises, test answers with a checker.
220
+ - Name a source for facts. Where it fits; never a listing condition.
221
+
222
+ ## Catalog entry
223
+
224
+ - Listed by a pull request to <https://github.com/lernapps/apps>; steps: skill `lernapps-listing`.
225
+
226
+ ### `entry-from-schema`: Fill the entry from the published schema
227
+
228
+ ```rule
229
+ id: entry-from-schema
230
+ scope: listing
231
+ severity: error
232
+ ```
233
+
234
+ - Fetch the entry schema each time; never from memory or another app.
235
+ - Every value from the creator's answers, the plan or the app; never invented.
236
+
237
+ ### `entry-links-resolve`: Every link of the entry resolves
238
+
239
+ ```rule
240
+ id: entry-links-resolve
241
+ scope: listing
242
+ severity: error
243
+ ```
244
+
245
+ - Each topic: path of an existing page, relative to the app's `url`; `<page>#<section>` names an element id there.
246
+ - Check against the deployed app: `lernapps check --entry <file>`.
247
+
248
+ ### `entry-fitness-matches`: Fitness values as measured
249
+
250
+ ```rule
251
+ id: entry-fitness-matches
252
+ scope: listing
253
+ severity: error
254
+ ```
255
+
256
+ - `fitness.storage`, `fitness.thirdParty` from what the app does; `lernapps check --report <file>` measures it.
257
+ - Anything in `localStorage` or `sessionStorage`, also what the app only reads on loading and keeps after an input (an
258
+ assistant chosen for the tutor, an answer being written) → `storage: device`; loads from another server after a click → `thirdParty: on-click`.