@renoxar/koolie 1.25.0

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 (693) hide show
  1. package/.gitattributes +16 -0
  2. package/.gitignore +51 -0
  3. package/.koolie/QUELLREPOSITORIUM.md +18 -0
  4. package/.koolie/core/CHANGELOG.md +11832 -0
  5. package/.koolie/core/LICENSE +674 -0
  6. package/.koolie/core/LICENSE-HINWEIS.md +98 -0
  7. package/.koolie/core/OWNERS.md +36 -0
  8. package/.koolie/core/VERSION +1 -0
  9. package/.koolie/core/banner.py +397 -0
  10. package/.koolie/core/build/README.md +34 -0
  11. package/.koolie/core/build/assemble.py +354 -0
  12. package/.koolie/core/build/build-docx.py +194 -0
  13. package/.koolie/core/build/doc/00-kopf.md +18 -0
  14. package/.koolie/core/build/doc/01-executive-summary.md +24 -0
  15. package/.koolie/core/build/doc/02-zielbild.md +13 -0
  16. package/.koolie/core/build/doc/03-ziele-nichtziele.md +28 -0
  17. package/.koolie/core/build/doc/04-geltungsbereich.md +25 -0
  18. package/.koolie/core/build/doc/05-glossar.md +47 -0
  19. package/.koolie/core/build/doc/06-leitprinzipien.md +5 -0
  20. package/.koolie/core/build/doc/07-architektur.md +60 -0
  21. package/.koolie/core/build/doc/07a-abbildungsschicht.md +66 -0
  22. package/.koolie/core/build/doc/08-trennung.md +24 -0
  23. package/.koolie/core/build/doc/09-betriebsmodi.md +18 -0
  24. package/.koolie/core/build/doc/10-arbeitsablauf.md +5 -0
  25. package/.koolie/core/build/doc/11-datenschutz.md +5 -0
  26. package/.koolie/core/build/doc/12-sicherheit.md +5 -0
  27. package/.koolie/core/build/doc/13-risiko.md +5 -0
  28. package/.koolie/core/build/doc/14-rollen.md +9 -0
  29. package/.koolie/core/build/doc/15-referenzstruktur.md +124 -0
  30. package/.koolie/core/build/doc/16-agentenanweisung.md +8 -0
  31. package/.koolie/core/build/doc/17-overlay.md +29 -0
  32. package/.koolie/core/build/doc/18-skill-standard.md +5 -0
  33. package/.koolie/core/build/doc/19-skill-template.md +5 -0
  34. package/.koolie/core/build/doc/20-referenz-skills.md +70 -0
  35. package/.koolie/core/build/doc/21-prompts.md +53 -0
  36. package/.koolie/core/build/doc/22-checklisten.md +49 -0
  37. package/.koolie/core/build/doc/23-entscheidungsbaeume.md +29 -0
  38. package/.koolie/core/build/doc/24-onboarding.md +33 -0
  39. package/.koolie/core/build/doc/25-governance.md +35 -0
  40. package/.koolie/core/build/doc/26-qs-test.md +9 -0
  41. package/.koolie/core/build/doc/27-pilot.md +13 -0
  42. package/.koolie/core/build/doc/28-uebernahme.md +5 -0
  43. package/.koolie/core/build/doc/29-grenzen.md +87 -0
  44. package/.koolie/core/build/doc/30-roadmap.md +5 -0
  45. package/.koolie/core/build/doc/31-anhaenge.md +151 -0
  46. package/.koolie/core/build/doc/32-abschluss.md +92 -0
  47. package/.koolie/core/build/ref-a4.docx +0 -0
  48. package/.koolie/core/checklists/01-preflight.md +54 -0
  49. package/.koolie/core/checklists/02-privacy-context.md +51 -0
  50. package/.koolie/core/checklists/03-before-code-change.md +51 -0
  51. package/.koolie/core/checklists/04-review-ai-code.md +58 -0
  52. package/.koolie/core/checklists/05-testing.md +48 -0
  53. package/.koolie/core/checklists/06-security.md +50 -0
  54. package/.koolie/core/checklists/07-new-dependency.md +57 -0
  55. package/.koolie/core/checklists/08-merge-request.md +47 -0
  56. package/.koolie/core/checklists/09-onboarding.md +52 -0
  57. package/.koolie/core/checklists/10-project-adoption.md +74 -0
  58. package/.koolie/core/checklists/11-framework-release.md +71 -0
  59. package/.koolie/core/checklists/README.md +28 -0
  60. package/.koolie/core/clientmap.py +1358 -0
  61. package/.koolie/core/clients/README.md +113 -0
  62. package/.koolie/core/clients/_template/CLIENT_PACK.md +197 -0
  63. package/.koolie/core/clients/claude-code/CLIENT_PACK.md +383 -0
  64. package/.koolie/core/clients/claude-code/manifest.json +232 -0
  65. package/.koolie/core/clients/claude-code/root-template/.claude/README.md +127 -0
  66. package/.koolie/core/clients/cursor/CLIENT_PACK.md +229 -0
  67. package/.koolie/core/clients/cursor/manifest.json +330 -0
  68. package/.koolie/core/clients/cursor/root-template/.cursor/README.md +36 -0
  69. package/.koolie/core/clients/devin-desktop/CLIENT_PACK.md +251 -0
  70. package/.koolie/core/clients/devin-desktop/manifest.json +163 -0
  71. package/.koolie/core/clients/devin-desktop/root-template/.devin/README.md +79 -0
  72. package/.koolie/core/clients/kiro/CLIENT_PACK.md +223 -0
  73. package/.koolie/core/clients/kiro/manifest.json +300 -0
  74. package/.koolie/core/clients/kiro/root-template/.kiro/README.md +37 -0
  75. package/.koolie/core/clients/openai-codex/CLIENT_PACK.md +257 -0
  76. package/.koolie/core/clients/openai-codex/manifest.json +208 -0
  77. package/.koolie/core/clients/openai-codex/root-template/.codex/README.md +35 -0
  78. package/.koolie/core/decision-trees/01-context-allowed.md +46 -0
  79. package/.koolie/core/decision-trees/02-may-ai-do-task.md +47 -0
  80. package/.koolie/core/decision-trees/03-analyze-or-modify.md +50 -0
  81. package/.koolie/core/decision-trees/04-required-review.md +49 -0
  82. package/.koolie/core/decision-trees/05-stop-or-escalate.md +47 -0
  83. package/.koolie/core/decision-trees/06-rule-placement.md +58 -0
  84. package/.koolie/core/decision-trees/README.md +14 -0
  85. package/.koolie/core/docs/ADOPTION_GUIDE.md +582 -0
  86. package/.koolie/core/docs/DOCUMENTATION_STANDARD.md +91 -0
  87. package/.koolie/core/docs/PLACEHOLDER_REGISTRY.md +79 -0
  88. package/.koolie/core/docs/ROADMAP.md +848 -0
  89. package/.koolie/core/docs/RUNTIME_GLOSSARY.md +113 -0
  90. package/.koolie/core/examples/README.md +11 -0
  91. package/.koolie/core/examples/example-ergebnisbericht.md +31 -0
  92. package/.koolie/core/examples/example-mr-description.md +31 -0
  93. package/.koolie/core/examples/example-overlay-runtime.md +48 -0
  94. package/.koolie/core/framework/core/00-principles.md +93 -0
  95. package/.koolie/core/framework/core/01-governance.md +58 -0
  96. package/.koolie/core/framework/core/02-privacy.md +141 -0
  97. package/.koolie/core/framework/core/03-security.md +86 -0
  98. package/.koolie/core/framework/core/04-quality.md +48 -0
  99. package/.koolie/core/framework/core/05-working-model.md +199 -0
  100. package/.koolie/core/framework/core/06-prompting-rules.md +51 -0
  101. package/.koolie/core/framework/core/07-review-rules.md +52 -0
  102. package/.koolie/core/framework/core/08-skill-conventions.md +115 -0
  103. package/.koolie/core/framework/core/09-risk-model.md +87 -0
  104. package/.koolie/core/framework/core/10-error-escalation.md +53 -0
  105. package/.koolie/core/framework/org-policies/MAPPING_CLASSIFICATION.md +16 -0
  106. package/.koolie/core/framework/org-policies/README.md +29 -0
  107. package/.koolie/core/framework/overlay-patterns/general/documents/branching-strategy/muster-general.md +43 -0
  108. package/.koolie/core/framework/overlay-patterns/general/documents/coding-guidelines/muster-general.md +82 -0
  109. package/.koolie/core/framework/overlay-patterns/general/documents/definition-of-done/muster-general.md +52 -0
  110. package/.koolie/core/framework/overlay-patterns/general/documents/definition-of-ready/muster-general.md +54 -0
  111. package/.koolie/core/framework/overlay-patterns/general/documents/quality/muster-general.md +59 -0
  112. package/.koolie/core/framework/overlay-patterns/general/documents/security/muster-general.md +52 -0
  113. package/.koolie/core/framework/overlay-patterns/general.md +150 -0
  114. package/.koolie/core/framework/role-packs/README.md +63 -0
  115. package/.koolie/core/framework/role-packs/_template/ROLE_PACK.md +58 -0
  116. package/.koolie/core/framework/role-packs/requirements-engineering/ROLE_PACK.md +158 -0
  117. package/.koolie/core/framework/role-packs/requirements-engineering/runtime/30-role-requirements-engineering.md +88 -0
  118. package/.koolie/core/framework/role-packs/requirements-engineering/skills/role-re-ticket/CHANGELOG.md +10 -0
  119. package/.koolie/core/framework/role-packs/requirements-engineering/skills/role-re-ticket/EXAMPLES.md +148 -0
  120. package/.koolie/core/framework/role-packs/requirements-engineering/skills/role-re-ticket/SKILL.md +195 -0
  121. package/.koolie/core/framework/role-packs/requirements-engineering/skills/role-re-ticket/TESTS.md +22 -0
  122. package/.koolie/core/framework/role-packs/software-development/ROLE_PACK.md +95 -0
  123. package/.koolie/core/framework/role-packs/software-development/runtime/30-role-software-development.md +26 -0
  124. package/.koolie/core/framework/runtime/agents/fw-reviewer.md +34 -0
  125. package/.koolie/core/framework/runtime/client-settings.json +3 -0
  126. package/.koolie/core/framework/runtime/hooks.json +20 -0
  127. package/.koolie/core/framework/runtime/mcp-config.example.json +4 -0
  128. package/.koolie/core/framework/runtime/permissions.json +106 -0
  129. package/.koolie/core/framework/runtime/root-instruction-local.example.md +19 -0
  130. package/.koolie/core/framework/runtime/root-instruction.md +116 -0
  131. package/.koolie/core/framework/runtime/rules/00-framework-core.md +49 -0
  132. package/.koolie/core/framework/runtime/rules/10-privacy-security.md +49 -0
  133. package/.koolie/core/framework/runtime/rules/15-development-rules.md +41 -0
  134. package/.koolie/core/framework/runtime/rules/16-plan-spezifikation.md +32 -0
  135. package/.koolie/core/framework/runtime/rules/20-project-overlay.md +60 -0
  136. package/.koolie/core/framework/skills/fw-bugfix-prepare/CHANGELOG.md +14 -0
  137. package/.koolie/core/framework/skills/fw-bugfix-prepare/EXAMPLES.md +57 -0
  138. package/.koolie/core/framework/skills/fw-bugfix-prepare/SKILL.md +177 -0
  139. package/.koolie/core/framework/skills/fw-bugfix-prepare/TESTS.md +15 -0
  140. package/.koolie/core/framework/skills/fw-change-analyze/CHANGELOG.md +12 -0
  141. package/.koolie/core/framework/skills/fw-change-analyze/EXAMPLES.md +66 -0
  142. package/.koolie/core/framework/skills/fw-change-analyze/SKILL.md +167 -0
  143. package/.koolie/core/framework/skills/fw-change-analyze/TESTS.md +16 -0
  144. package/.koolie/core/framework/skills/fw-change-small/CHANGELOG.md +13 -0
  145. package/.koolie/core/framework/skills/fw-change-small/EXAMPLES.md +68 -0
  146. package/.koolie/core/framework/skills/fw-change-small/SKILL.md +175 -0
  147. package/.koolie/core/framework/skills/fw-change-small/TESTS.md +13 -0
  148. package/.koolie/core/framework/skills/fw-code-explain/CHANGELOG.md +11 -0
  149. package/.koolie/core/framework/skills/fw-code-explain/EXAMPLES.md +61 -0
  150. package/.koolie/core/framework/skills/fw-code-explain/SKILL.md +163 -0
  151. package/.koolie/core/framework/skills/fw-code-explain/TESTS.md +11 -0
  152. package/.koolie/core/framework/skills/fw-docs-update/CHANGELOG.md +10 -0
  153. package/.koolie/core/framework/skills/fw-docs-update/EXAMPLES.md +59 -0
  154. package/.koolie/core/framework/skills/fw-docs-update/SKILL.md +160 -0
  155. package/.koolie/core/framework/skills/fw-docs-update/TESTS.md +12 -0
  156. package/.koolie/core/framework/skills/fw-error-analyze/CHANGELOG.md +10 -0
  157. package/.koolie/core/framework/skills/fw-error-analyze/EXAMPLES.md +67 -0
  158. package/.koolie/core/framework/skills/fw-error-analyze/SKILL.md +160 -0
  159. package/.koolie/core/framework/skills/fw-error-analyze/TESTS.md +12 -0
  160. package/.koolie/core/framework/skills/fw-mr-description/CHANGELOG.md +12 -0
  161. package/.koolie/core/framework/skills/fw-mr-description/EXAMPLES.md +69 -0
  162. package/.koolie/core/framework/skills/fw-mr-description/SKILL.md +170 -0
  163. package/.koolie/core/framework/skills/fw-mr-description/TESTS.md +12 -0
  164. package/.koolie/core/framework/skills/fw-overlay-pflege/CHANGELOG.md +7 -0
  165. package/.koolie/core/framework/skills/fw-overlay-pflege/EXAMPLES.md +48 -0
  166. package/.koolie/core/framework/skills/fw-overlay-pflege/SKILL.md +147 -0
  167. package/.koolie/core/framework/skills/fw-overlay-pflege/TESTS.md +13 -0
  168. package/.koolie/core/framework/skills/fw-plan/CHANGELOG.md +14 -0
  169. package/.koolie/core/framework/skills/fw-plan/EXAMPLES.md +69 -0
  170. package/.koolie/core/framework/skills/fw-plan/SKILL.md +168 -0
  171. package/.koolie/core/framework/skills/fw-plan/TESTS.md +14 -0
  172. package/.koolie/core/framework/skills/fw-refactor/CHANGELOG.md +10 -0
  173. package/.koolie/core/framework/skills/fw-refactor/EXAMPLES.md +70 -0
  174. package/.koolie/core/framework/skills/fw-refactor/SKILL.md +173 -0
  175. package/.koolie/core/framework/skills/fw-refactor/TESTS.md +14 -0
  176. package/.koolie/core/framework/skills/fw-repo-analyze/CHANGELOG.md +10 -0
  177. package/.koolie/core/framework/skills/fw-repo-analyze/EXAMPLES.md +52 -0
  178. package/.koolie/core/framework/skills/fw-repo-analyze/SKILL.md +149 -0
  179. package/.koolie/core/framework/skills/fw-repo-analyze/TESTS.md +11 -0
  180. package/.koolie/core/framework/skills/fw-review-support/CHANGELOG.md +12 -0
  181. package/.koolie/core/framework/skills/fw-review-support/EXAMPLES.md +69 -0
  182. package/.koolie/core/framework/skills/fw-review-support/SKILL.md +179 -0
  183. package/.koolie/core/framework/skills/fw-review-support/TESTS.md +13 -0
  184. package/.koolie/core/framework/skills/fw-tests/CHANGELOG.md +9 -0
  185. package/.koolie/core/framework/skills/fw-tests/EXAMPLES.md +65 -0
  186. package/.koolie/core/framework/skills/fw-tests/SKILL.md +169 -0
  187. package/.koolie/core/framework/skills/fw-tests/TESTS.md +12 -0
  188. package/.koolie/core/framework/tech-packs/README.md +15 -0
  189. package/.koolie/core/framework/tech-packs/_template/TECH_PACK.md +61 -0
  190. package/.koolie/core/governance/ADOPTION_REGISTRY.md +89 -0
  191. package/.koolie/core/governance/CHANGE_REQUEST_TEMPLATE.md +60 -0
  192. package/.koolie/core/governance/DECISION_LOG.md +779 -0
  193. package/.koolie/core/governance/EXCEPTION_PROCESS.md +31 -0
  194. package/.koolie/core/governance/FEEDBACK_PROCESS.md +34 -0
  195. package/.koolie/core/governance/FRAMEWORK_DEV_PROFILE.md +135 -0
  196. package/.koolie/core/governance/INCIDENT_HANDLING.md +47 -0
  197. package/.koolie/core/governance/PRIORITY_HIERARCHY.md +61 -0
  198. package/.koolie/core/governance/RACI.md +37 -0
  199. package/.koolie/core/governance/RELEASE_PROCESS.md +183 -0
  200. package/.koolie/core/governance/change-requests/CR-2026-001-definition-release-1-0-0.md +67 -0
  201. package/.koolie/core/governance/change-requests/CR-2026-002-client-packs.md +63 -0
  202. package/.koolie/core/governance/change-requests/CR-2026-003-install-client-schalter.md +70 -0
  203. package/.koolie/core/governance/change-requests/CR-2026-004-client-pack-claude-code.md +82 -0
  204. package/.koolie/core/governance/change-requests/CR-2026-005-kern-neutralisierung.md +75 -0
  205. package/.koolie/core/governance/change-requests/CR-2026-006-gemeinsame-skill-quelle.md +77 -0
  206. package/.koolie/core/governance/change-requests/CR-2026-007-geteilte-kernbestandteile.md +80 -0
  207. package/.koolie/core/governance/change-requests/CR-2026-008-berechtigungen-und-hooks.md +85 -0
  208. package/.koolie/core/governance/change-requests/CR-2026-009-umbenennung-leitwerk.md +77 -0
  209. package/.koolie/core/governance/change-requests/CR-2026-010-restduplikation.md +73 -0
  210. package/.koolie/core/governance/change-requests/CR-2026-011-hauptdokument.md +72 -0
  211. package/.koolie/core/governance/change-requests/CR-2026-012-schreibschutz-kernverzeichnis.md +106 -0
  212. package/.koolie/core/governance/change-requests/CR-2026-013-validator-blindstellen.md +128 -0
  213. package/.koolie/core/governance/change-requests/CR-2026-014-kurzform-langform.md +125 -0
  214. package/.koolie/core/governance/change-requests/CR-2026-015-versionskette.md +150 -0
  215. package/.koolie/core/governance/change-requests/CR-2026-016-ap2-claude-code.md +127 -0
  216. package/.koolie/core/governance/change-requests/CR-2026-017-ladebedingungen-claude-code.md +173 -0
  217. package/.koolie/core/governance/change-requests/CR-2026-018-quellenliste-claude-code.md +121 -0
  218. package/.koolie/core/governance/change-requests/CR-2026-019-strukturentscheidungen-fortschreiben.md +143 -0
  219. package/.koolie/core/governance/change-requests/CR-2026-020-akteursbezeichnung.md +118 -0
  220. package/.koolie/core/governance/change-requests/CR-2026-021-hook-interpreter.md +113 -0
  221. package/.koolie/core/governance/change-requests/CR-2026-022-artefaktversionen.md +73 -0
  222. package/.koolie/core/governance/change-requests/CR-2026-023-shell-lesesperre.md +128 -0
  223. package/.koolie/core/governance/change-requests/CR-2026-024-clientbindungen.md +78 -0
  224. package/.koolie/core/governance/change-requests/CR-2026-025-betriebsmodi.md +110 -0
  225. package/.koolie/core/governance/change-requests/CR-2026-026-fail-closed.md +134 -0
  226. package/.koolie/core/governance/change-requests/CR-2026-027-zeichenlimit-einstufung.md +105 -0
  227. package/.koolie/core/governance/change-requests/CR-2026-028-berechtigungsmodi.md +130 -0
  228. package/.koolie/core/governance/change-requests/CR-2026-029-hook-ablageort.md +115 -0
  229. package/.koolie/core/governance/change-requests/CR-2026-030-lesende-werkzeuge.md +143 -0
  230. package/.koolie/core/governance/change-requests/CR-2026-031-regelquellen-ausserhalb.md +182 -0
  231. package/.koolie/core/governance/change-requests/CR-2026-032-fremde-skill-ablage.md +151 -0
  232. package/.koolie/core/governance/change-requests/CR-2026-033-modusabhaengige-durchsetzung.md +131 -0
  233. package/.koolie/core/governance/change-requests/CR-2026-034-nachweisbedingungen.md +116 -0
  234. package/.koolie/core/governance/change-requests/CR-2026-035-readme-in-der-regelablage.md +115 -0
  235. package/.koolie/core/governance/change-requests/CR-2026-036-ortsangaben-hook-konfiguration.md +108 -0
  236. package/.koolie/core/governance/change-requests/CR-2026-037-meldender-hook-clientgebunden.md +133 -0
  237. package/.koolie/core/governance/change-requests/CR-2026-038-importsteuerung.md +159 -0
  238. package/.koolie/core/governance/change-requests/CR-2026-039-normative-saetze-in-kommentaren.md +124 -0
  239. package/.koolie/core/governance/change-requests/CR-2026-040-erh01-ist-clientgebunden.md +115 -0
  240. package/.koolie/core/governance/change-requests/CR-2026-041-s5-nicht-abbildbar.md +128 -0
  241. package/.koolie/core/governance/change-requests/CR-2026-042-abwesenheitsnachweis-suchwerkzeug.md +102 -0
  242. package/.koolie/core/governance/change-requests/CR-2026-043-validator-gibt-trefferwerte-aus.md +135 -0
  243. package/.koolie/core/governance/change-requests/CR-2026-044-aktivierungspruefung-clientgebunden.md +112 -0
  244. package/.koolie/core/governance/change-requests/CR-2026-045-update-verliert-die-clientwahl.md +116 -0
  245. package/.koolie/core/governance/change-requests/CR-2026-046-erstinstallation-ueberschreibt-projektdatei.md +125 -0
  246. package/.koolie/core/governance/change-requests/CR-2026-047-zusagen-je-zugriffskanal.md +133 -0
  247. package/.koolie/core/governance/change-requests/CR-2026-048-modusgrenze-ohne-durchsetzung.md +137 -0
  248. package/.koolie/core/governance/change-requests/CR-2026-049-sondenlauf-kodierungsabhaengig.md +126 -0
  249. package/.koolie/core/governance/change-requests/CR-2026-050-allowed-tools-und-verworfene-permissions.md +110 -0
  250. package/.koolie/core/governance/change-requests/CR-2026-051-quellenkarte-und-ueberholter-stand.md +110 -0
  251. package/.koolie/core/governance/change-requests/CR-2026-052-drei-regelkonflikte.md +166 -0
  252. package/.koolie/core/governance/change-requests/CR-2026-053-lesesperre-und-entwicklungsprofil.md +144 -0
  253. package/.koolie/core/governance/change-requests/CR-2026-054-aktivierung-verlangt-aktivitaet.md +124 -0
  254. package/.koolie/core/governance/change-requests/CR-2026-055-domain-ausnahme-ohne-mechanismus.md +173 -0
  255. package/.koolie/core/governance/change-requests/CR-2026-056-eingabeschema-und-pfadidentitaet.md +245 -0
  256. package/.koolie/core/governance/change-requests/CR-2026-057-disallowed-tools-und-s3.md +148 -0
  257. package/.koolie/core/governance/change-requests/CR-2026-058-unteragent-reichweite.md +203 -0
  258. package/.koolie/core/governance/change-requests/CR-2026-059-unteragent-tiefe-und-widerspruch.md +125 -0
  259. package/.koolie/core/governance/change-requests/CR-2026-060-stumme-brueche.md +170 -0
  260. package/.koolie/core/governance/change-requests/CR-2026-061-berechtigungsdatei-ohne-pruefung.md +169 -0
  261. package/.koolie/core/governance/change-requests/CR-2026-062-werkzeugabbildung-des-frontmatters.md +178 -0
  262. package/.koolie/core/governance/change-requests/CR-2026-063-skillaufruf-ohne-freigabe.md +207 -0
  263. package/.koolie/core/governance/change-requests/CR-2026-064-pruefregister-nicht-nachgezaehlt.md +141 -0
  264. package/.koolie/core/governance/change-requests/CR-2026-065-devin-suchwerkzeuge-erhoben.md +170 -0
  265. package/.koolie/core/governance/change-requests/CR-2026-066-schlitzdeckung-ohne-abgleich.md +153 -0
  266. package/.koolie/core/governance/change-requests/CR-2026-067-hookblock-und-praeparationsregister.md +140 -0
  267. package/.koolie/core/governance/change-requests/CR-2026-068-sondenlauf-nebenlaeufig.md +106 -0
  268. package/.koolie/core/governance/change-requests/CR-2026-069-bytecode-des-kerns.md +108 -0
  269. package/.koolie/core/governance/change-requests/CR-2026-070-d11-zaehler.md +114 -0
  270. package/.koolie/core/governance/change-requests/CR-2026-071-strukturentscheidungen-bestaetigen.md +322 -0
  271. package/.koolie/core/governance/change-requests/CR-2026-072-modulstatus-heben.md +315 -0
  272. package/.koolie/core/governance/change-requests/CR-2026-073-nicht-skill-traeger-heben.md +246 -0
  273. package/.koolie/core/governance/change-requests/CR-2026-074-restliche-nicht-skill-traeger-heben.md +271 -0
  274. package/.koolie/core/governance/change-requests/CR-2026-075-ap2-zielversion-devin-desktop.md +335 -0
  275. package/.koolie/core/governance/change-requests/CR-2026-076-erster-sitzungstest.md +455 -0
  276. package/.koolie/core/governance/change-requests/CR-2026-077-sitzungstest-schranken.md +425 -0
  277. package/.koolie/core/governance/change-requests/CR-2026-078-planung-nach-1-0-0.md +294 -0
  278. package/.koolie/core/governance/change-requests/CR-2026-079-umbenennung-vorziehen.md +233 -0
  279. package/.koolie/core/governance/change-requests/CR-2026-080-clientbindung-des-kerns.md +321 -0
  280. package/.koolie/core/governance/change-requests/CR-2026-081-produktnamen-im-kern.md +297 -0
  281. package/.koolie/core/governance/change-requests/CR-2026-082-sitzungstest-pi-ds-2.md +145 -0
  282. package/.koolie/core/governance/change-requests/CR-2026-083-sitzungstest-ne-sc.md +300 -0
  283. package/.koolie/core/governance/change-requests/CR-2026-084-trockenlauf-gegen-den-committeten-stand.md +117 -0
  284. package/.koolie/core/governance/change-requests/CR-2026-085-vorbedingungen-sitzungstest-5.md +182 -0
  285. package/.koolie/core/governance/change-requests/CR-2026-086-grenzfaelle-gegen-die-fassungen.md +164 -0
  286. package/.koolie/core/governance/change-requests/CR-2026-087-produktbeobachtung-quellenliste.md +206 -0
  287. package/.koolie/core/governance/change-requests/CR-2026-088-vorbedingungen-testblaetter.md +127 -0
  288. package/.koolie/core/governance/change-requests/CR-2026-089-herrichtung-uebungsrepositorium.md +226 -0
  289. package/.koolie/core/governance/change-requests/CR-2026-090-vorbedingungen-sitzungstest-5-zweiter-durchgang.md +255 -0
  290. package/.koolie/core/governance/change-requests/CR-2026-091-sitzungstest-5.md +163 -0
  291. package/.koolie/core/governance/change-requests/CR-2026-092-pruefmittelwort-und-buendelschnitt.md +226 -0
  292. package/.koolie/core/governance/change-requests/CR-2026-093-sechzehnte-praeparation.md +151 -0
  293. package/.koolie/core/governance/change-requests/CR-2026-094-testblaetter-buendel-1.md +113 -0
  294. package/.koolie/core/governance/change-requests/CR-2026-095-pruefapparat-filter.md +65 -0
  295. package/.koolie/core/governance/change-requests/CR-2026-096-vorbedingungen-buendel-2.md +225 -0
  296. package/.koolie/core/governance/change-requests/CR-2026-097-testblaetter-buendel-2.md +162 -0
  297. package/.koolie/core/governance/change-requests/CR-2026-098-anforderungen-auslieferung.md +93 -0
  298. package/.koolie/core/governance/change-requests/CR-2026-099-k74-und-vorbedingungen-buendel-3.md +119 -0
  299. package/.koolie/core/governance/change-requests/CR-2026-100-testblaetter-buendel-3.md +120 -0
  300. package/.koolie/core/governance/change-requests/CR-2026-101-k77-eigener-posten.md +165 -0
  301. package/.koolie/core/governance/change-requests/CR-2026-102-k77-entschieden.md +118 -0
  302. package/.koolie/core/governance/change-requests/CR-2026-103-vorbedingungen-buendel-4.md +76 -0
  303. package/.koolie/core/governance/change-requests/CR-2026-104-herrichtung-buendel-4.md +82 -0
  304. package/.koolie/core/governance/change-requests/CR-2026-105-messapparat-buendel-4.md +227 -0
  305. package/.koolie/core/governance/change-requests/CR-2026-106-uebergabe-einchecken.md +91 -0
  306. package/.koolie/core/governance/change-requests/CR-2026-107-uebergabe-im-release-commit.md +111 -0
  307. package/.koolie/core/governance/change-requests/CR-2026-108-testblaetter-buendel-4.md +118 -0
  308. package/.koolie/core/governance/change-requests/CR-2026-109-berichtsweg-des-aufraeumers.md +108 -0
  309. package/.koolie/core/governance/change-requests/CR-2026-110-vorbedingungen-des-nachlaufs.md +184 -0
  310. package/.koolie/core/governance/change-requests/CR-2026-111-der-apparat-auf-dem-weg-der-wiederaufnahme.md +127 -0
  311. package/.koolie/core/governance/change-requests/CR-2026-112-der-arbeitsplatz-im-kern.md +103 -0
  312. package/.koolie/core/governance/change-requests/CR-2026-113-nachlauf-buendel-4.md +103 -0
  313. package/.koolie/core/governance/change-requests/CR-2026-114-vorbedingungen-buendel-5.md +317 -0
  314. package/.koolie/core/governance/change-requests/CR-2026-115-herrichtung-buendel-5.md +244 -0
  315. package/.koolie/core/governance/change-requests/CR-2026-116-messtag-buendel-5.md +178 -0
  316. package/.koolie/core/governance/change-requests/CR-2026-117-sammelzellen-zentraler-katalog.md +251 -0
  317. package/.koolie/core/governance/change-requests/CR-2026-118-quellenzuordnung-matrixzeilen.md +115 -0
  318. package/.koolie/core/governance/change-requests/CR-2026-119-umbenennung-koolie.md +204 -0
  319. package/.koolie/core/governance/change-requests/CR-2026-120-ap2-rest-devin-desktop.md +96 -0
  320. package/.koolie/core/governance/change-requests/CR-2026-121-verify-marker-abschaffen.md +185 -0
  321. package/.koolie/core/governance/change-requests/CR-2026-122-umbenennung-koolie-lauf.md +131 -0
  322. package/.koolie/core/governance/change-requests/CR-2026-123-vortrag-und-namensabsatz.md +170 -0
  323. package/.koolie/core/governance/change-requests/CR-2026-124-hauptdokument-ap11.md +237 -0
  324. package/.koolie/core/governance/change-requests/CR-2026-125-word-fassung-und-blinder-fleck.md +204 -0
  325. package/.koolie/core/governance/change-requests/CR-2026-126-lizenz-gpl3.md +112 -0
  326. package/.koolie/core/governance/change-requests/CR-2026-127-gegenzeichnung-rollenfrage.md +96 -0
  327. package/.koolie/core/governance/change-requests/CR-2026-128-freigabelauf-1.0.0.md +278 -0
  328. package/.koolie/core/governance/change-requests/CR-2026-129-archiv-zeilenenden.md +90 -0
  329. package/.koolie/core/governance/change-requests/CR-2026-130-reihenfolge-des-hebens.md +204 -0
  330. package/.koolie/core/governance/change-requests/CR-2026-131-chronik-und-vorlage.md +194 -0
  331. package/.koolie/core/governance/change-requests/CR-2026-132-erhebung-openai-codex.md +185 -0
  332. package/.koolie/core/governance/change-requests/CR-2026-133-bau-openai-codex.md +97 -0
  333. package/.koolie/core/governance/change-requests/CR-2026-134-uebergabe-lokal.md +117 -0
  334. package/.koolie/core/governance/change-requests/CR-2026-135-pfadlisten-nul-getrennt.md +139 -0
  335. package/.koolie/core/governance/change-requests/CR-2026-136-overlay-werte-einordnung.md +156 -0
  336. package/.koolie/core/governance/change-requests/CR-2026-137-kopierweg-kern.md +144 -0
  337. package/.koolie/core/governance/change-requests/CR-2026-138-overlay-muster-general.md +118 -0
  338. package/.koolie/core/governance/change-requests/CR-2026-139-overlay-muster-dokumente.md +105 -0
  339. package/.koolie/core/governance/change-requests/CR-2026-140-installer-je-zielsystem.md +120 -0
  340. package/.koolie/core/governance/change-requests/CR-2026-141-lieferumfang.md +123 -0
  341. package/.koolie/core/governance/change-requests/CR-2026-142-dokumentationsstandard.md +90 -0
  342. package/.koolie/core/governance/change-requests/CR-2026-143-klasse-b-core-laufzeit.md +89 -0
  343. package/.koolie/core/governance/change-requests/CR-2026-144-klasse-b-governance.md +90 -0
  344. package/.koolie/core/governance/change-requests/CR-2026-145-klasse-b-skills.md +81 -0
  345. package/.koolie/core/governance/change-requests/CR-2026-146-code-pack-posten.md +84 -0
  346. package/.koolie/core/governance/change-requests/CR-2026-147-regel-register-posten.md +78 -0
  347. package/.koolie/core/governance/change-requests/CR-2026-148-mehrprojekt-tokenlast.md +70 -0
  348. package/.koolie/core/governance/change-requests/CR-2026-149-regelablage-pfadtoken.md +71 -0
  349. package/.koolie/core/governance/change-requests/CR-2026-150-client-pack-kiro.md +76 -0
  350. package/.koolie/core/governance/change-requests/CR-2026-151-skill-anweisungen.md +71 -0
  351. package/.koolie/core/governance/change-requests/CR-2026-152-testblaetter-modellwechsel.md +78 -0
  352. package/.koolie/core/governance/change-requests/CR-2026-153-attributionszeile.md +88 -0
  353. package/.koolie/core/governance/change-requests/CR-2026-154-auffindbarkeit.md +102 -0
  354. package/.koolie/core/governance/change-requests/CR-2026-155-client-pack-cursor.md +80 -0
  355. package/.koolie/core/governance/change-requests/CR-2026-156-mandat-und-reibung.md +100 -0
  356. package/.koolie/core/governance/change-requests/CR-2026-157-mcp-anbindung.md +93 -0
  357. package/.koolie/core/governance/change-requests/CR-2026-158-registerpflege.md +69 -0
  358. package/.koolie/core/governance/change-requests/CR-2026-159-powershell.md +49 -0
  359. package/.koolie/core/governance/change-requests/CR-2026-160-messapparat.md +59 -0
  360. package/.koolie/core/governance/change-requests/CR-2026-161-pruefwerkzeuge.md +52 -0
  361. package/.koolie/core/governance/change-requests/CR-2026-162-schutzschicht.md +65 -0
  362. package/.koolie/core/governance/change-requests/CR-2026-163-pfadsemantik.md +61 -0
  363. package/.koolie/core/governance/change-requests/CR-2026-164-modi-ausnahmen.md +65 -0
  364. package/.koolie/core/governance/change-requests/CR-2026-165-installer-banner.md +406 -0
  365. package/.koolie/core/governance/change-requests/CR-2026-166-nachlauf-aufzeichnungen.md +59 -0
  366. package/.koolie/core/governance/change-requests/CR-2026-167-einsatzarchitektur.md +60 -0
  367. package/.koolie/core/governance/change-requests/CR-2026-168-paketquellen.md +64 -0
  368. package/.koolie/core/governance/change-requests/CR-2026-169-modusbindung-messfragen.md +58 -0
  369. package/.koolie/core/governance/change-requests/CR-2026-170-erste-veroeffentlichung.md +62 -0
  370. package/.koolie/core/governance/change-requests/CR-2026-171-befehl-im-projektverzeichnis.md +57 -0
  371. package/.koolie/core/governance/change-requests/CR-2026-172-auftritt-npm-suche.md +58 -0
  372. package/.koolie/core/install.py +2402 -0
  373. package/.koolie/core/install_dialog.py +227 -0
  374. package/.koolie/core/koexistenz.py +112 -0
  375. package/.koolie/core/mandat.py +605 -0
  376. package/.koolie/core/onboarding/COMPLETION_CRITERIA.md +37 -0
  377. package/.koolie/core/onboarding/GUIDE.md +103 -0
  378. package/.koolie/core/onboarding/KNOWLEDGE_CHECK.md +48 -0
  379. package/.koolie/core/onboarding/MENTOR_CHECKLIST.md +40 -0
  380. package/.koolie/core/onboarding/QUICKSTART.md +50 -0
  381. package/.koolie/core/onboarding/REFERENCE.md +69 -0
  382. package/.koolie/core/onboarding/exercises/EXERCISES.md +78 -0
  383. package/.koolie/core/onboarding/exercises/README.md +120 -0
  384. package/.koolie/core/pilot/METRICS.md +59 -0
  385. package/.koolie/core/pilot/PILOT_CONCEPT.md +42 -0
  386. package/.koolie/core/prompts/01-understand-codebase.md +99 -0
  387. package/.koolie/core/prompts/02-impact-analysis.md +104 -0
  388. package/.koolie/core/prompts/03-implementation-planning.md +102 -0
  389. package/.koolie/core/prompts/04-code-generation.md +100 -0
  390. package/.koolie/core/prompts/05-test-generation.md +103 -0
  391. package/.koolie/core/prompts/06-refactoring.md +102 -0
  392. package/.koolie/core/prompts/07-debugging.md +97 -0
  393. package/.koolie/core/prompts/08-security-review.md +92 -0
  394. package/.koolie/core/prompts/09-performance-analysis.md +89 -0
  395. package/.koolie/core/prompts/10-documentation.md +91 -0
  396. package/.koolie/core/prompts/11-merge-request-review.md +94 -0
  397. package/.koolie/core/prompts/12-developer-training.md +90 -0
  398. package/.koolie/core/prompts/README.md +88 -0
  399. package/.koolie/core/templates/MR_AI_DISCLOSURE.md +37 -0
  400. package/.koolie/core/templates/PLAN_TEMPLATE.md +57 -0
  401. package/.koolie/core/templates/SKILL_TEMPLATE.md +159 -0
  402. package/.koolie/core/templates/project-overlay/OVERLAY.md +315 -0
  403. package/.koolie/core/templates/project-overlay/documents/README.md +43 -0
  404. package/.koolie/core/templates/project-overlay/documents/ai-governance/.gitkeep.md +3 -0
  405. package/.koolie/core/templates/project-overlay/documents/ai-process-model/.gitkeep.md +3 -0
  406. package/.koolie/core/templates/project-overlay/documents/architecture/.gitkeep.md +3 -0
  407. package/.koolie/core/templates/project-overlay/documents/architecture/decisions/README.md +3 -0
  408. package/.koolie/core/templates/project-overlay/documents/branching-strategy/.gitkeep.md +3 -0
  409. package/.koolie/core/templates/project-overlay/documents/coding-guidelines/.gitkeep.md +3 -0
  410. package/.koolie/core/templates/project-overlay/documents/definition-of-done/.gitkeep.md +3 -0
  411. package/.koolie/core/templates/project-overlay/documents/definition-of-ready/.gitkeep.md +3 -0
  412. package/.koolie/core/templates/project-overlay/documents/deployment/.gitkeep.md +3 -0
  413. package/.koolie/core/templates/project-overlay/documents/glossary/.gitkeep.md +3 -0
  414. package/.koolie/core/templates/project-overlay/documents/quality/.gitkeep.md +3 -0
  415. package/.koolie/core/templates/project-overlay/documents/roadmap/.gitkeep.md +3 -0
  416. package/.koolie/core/templates/project-overlay/documents/roles/.gitkeep.md +3 -0
  417. package/.koolie/core/templates/project-overlay/documents/security/.gitkeep.md +3 -0
  418. package/.koolie/core/templates/project-overlay/exceptions/EXCEPTIONS.md +9 -0
  419. package/.koolie/core/templates/project-overlay/forbidden-terms.txt +8 -0
  420. package/.koolie/core/templates/project-overlay/overlay-manifest.yaml +73 -0
  421. package/.koolie/core/templates/rules/21-overlay-TEMPLATE.md.template +28 -0
  422. package/.koolie/core/templates/rules/40-tech-TEMPLATE.md.template +33 -0
  423. package/.koolie/core/tests/EDGE_CASES.md +67 -0
  424. package/.koolie/core/tests/TEST_CATALOG.md +170 -0
  425. package/.koolie/core/tests/erhebungen/README.md +326 -0
  426. package/.koolie/core/tests/erhebungen/ablage.py +357 -0
  427. package/.koolie/core/tests/erhebungen/apparat/__init__.py +22 -0
  428. package/.koolie/core/tests/erhebungen/apparat/baum.py +214 -0
  429. package/.koolie/core/tests/erhebungen/apparat/belege.py +91 -0
  430. package/.koolie/core/tests/erhebungen/apparat/clients.py +321 -0
  431. package/.koolie/core/tests/erhebungen/apparat/freigabe.py +74 -0
  432. package/.koolie/core/tests/erhebungen/apparat/kontingent.py +64 -0
  433. package/.koolie/core/tests/erhebungen/apparat/laeufer.py +155 -0
  434. package/.koolie/core/tests/erhebungen/apparat/reihe.py +202 -0
  435. package/.koolie/core/tests/erhebungen/apparat/selbsttest.py +280 -0
  436. package/.koolie/core/tests/erhebungen/apparat/stand.py +30 -0
  437. package/.koolie/core/tests/erhebungen/apparat/vorpruefung.py +70 -0
  438. package/.koolie/core/tests/erhebungen/auswerten-b4.py +468 -0
  439. package/.koolie/core/tests/erhebungen/auswerten-b5.py +517 -0
  440. package/.koolie/core/tests/erhebungen/auswerten-dd.py +172 -0
  441. package/.koolie/core/tests/erhebungen/baeume-b4.py +334 -0
  442. package/.koolie/core/tests/erhebungen/baeume-b5.py +339 -0
  443. package/.koolie/core/tests/erhebungen/baeume_loeschen.py +138 -0
  444. package/.koolie/core/tests/erhebungen/cc-overlay-fuellen.py +277 -0
  445. package/.koolie/core/tests/erhebungen/dossier-b4.py +178 -0
  446. package/.koolie/core/tests/erhebungen/dossier-b5.py +202 -0
  447. package/.koolie/core/tests/erhebungen/historie-bauen-b4.py +642 -0
  448. package/.koolie/core/tests/erhebungen/k-bauen-b3.py +841 -0
  449. package/.koolie/core/tests/erhebungen/lauf-dd.py +146 -0
  450. package/.koolie/core/tests/erhebungen/lauf.py +114 -0
  451. package/.koolie/core/tests/erhebungen/mcp-waechter.py +278 -0
  452. package/.koolie/core/tests/erhebungen/messbaum-schnitt.py +256 -0
  453. package/.koolie/core/tests/erhebungen/messen.py +72 -0
  454. package/.koolie/core/tests/erhebungen/node-waechter.py +74 -0
  455. package/.koolie/core/tests/erhebungen/packaktivierung.py +403 -0
  456. package/.koolie/core/tests/erhebungen/prompts-schreiben-b4.py +210 -0
  457. package/.koolie/core/tests/erhebungen/prompts-schreiben-b5.py +251 -0
  458. package/.koolie/core/tests/erhebungen/reihe-b4.py +171 -0
  459. package/.koolie/core/tests/erhebungen/reihe-b5.py +172 -0
  460. package/.koolie/core/tests/erhebungen/stand-b4.py +135 -0
  461. package/.koolie/core/tests/erhebungen/stand-b5.py +137 -0
  462. package/.koolie/core/tests/erhebungen/trust-b4.py +56 -0
  463. package/.koolie/core/tests/erhebungen/trust-b5.py +56 -0
  464. package/.koolie/core/tests/erhebungen/turn2-schreiben-b4.py +105 -0
  465. package/.koolie/core/tests/erhebungen/umgebungen-bauen-b4.py +377 -0
  466. package/.koolie/core/tests/erhebungen/umgebungen-bauen-b5.py +363 -0
  467. package/.koolie/core/tests/erhebungen/zaehlen46.py +74 -0
  468. package/.koolie/core/tests/erhebungen/zustand-b4.py +82 -0
  469. package/.koolie/core/tests/erhebungen/zustand-b5.py +82 -0
  470. package/.koolie/core/tests/protocols/2026-09-10-AP2-claude-code-wirkungsnachweise.md +194 -0
  471. package/.koolie/core/tests/protocols/2026-09-10-AP2-claude-code.md +468 -0
  472. package/.koolie/core/tests/protocols/2026-09-10-CR-2026-020-akteursbezeichnung.md +99 -0
  473. package/.koolie/core/tests/protocols/2026-09-10-CR-2026-021-hook-interpreter.md +138 -0
  474. package/.koolie/core/tests/protocols/2026-09-10-CR-2026-022-artefaktversionen.md +87 -0
  475. package/.koolie/core/tests/protocols/2026-09-10-CR-2026-023-shell-lesesperre.md +135 -0
  476. package/.koolie/core/tests/protocols/2026-09-10-CR-2026-024-clientbindungen.md +98 -0
  477. package/.koolie/core/tests/protocols/2026-09-10-FW-DS-03.md +90 -0
  478. package/.koolie/core/tests/protocols/2026-09-10-FW-KO-01.md +105 -0
  479. package/.koolie/core/tests/protocols/2026-09-10-FW-KO-02.md +123 -0
  480. package/.koolie/core/tests/protocols/2026-09-10-FW-KO-04.md +73 -0
  481. package/.koolie/core/tests/protocols/2026-09-10-FW-RE-02.md +99 -0
  482. package/.koolie/core/tests/protocols/2026-09-10-FW-VN-01-wiederholung.md +108 -0
  483. package/.koolie/core/tests/protocols/2026-09-10-FW-VN-01.md +249 -0
  484. package/.koolie/core/tests/protocols/2026-09-10-FW-ZA-05.md +99 -0
  485. package/.koolie/core/tests/protocols/2026-09-11-AP2-devin-desktop.md +257 -0
  486. package/.koolie/core/tests/protocols/2026-09-11-CR-2026-026-fail-closed.md +113 -0
  487. package/.koolie/core/tests/protocols/2026-09-11-erhebungen-K21-K26.md +243 -0
  488. package/.koolie/core/tests/protocols/2026-09-11-wirkungsnachweise-0.26.0.md +101 -0
  489. package/.koolie/core/tests/protocols/2026-09-12-B01-allowed-tools.md +152 -0
  490. package/.koolie/core/tests/protocols/2026-09-12-B04-B05-gegenpruefung.md +204 -0
  491. package/.koolie/core/tests/protocols/2026-09-12-erhebungen-K28-S5-B9-bypass.md +268 -0
  492. package/.koolie/core/tests/protocols/2026-09-12-mehrprojekt-arbeitsbereich.md +154 -0
  493. package/.koolie/core/tests/protocols/2026-09-12-wirkungsnachweise-0.26.1.md +126 -0
  494. package/.koolie/core/tests/protocols/2026-09-12-wirkungsnachweise-0.27.0.md +114 -0
  495. package/.koolie/core/tests/protocols/2026-09-12-wirkungsnachweise-0.28.0.md +129 -0
  496. package/.koolie/core/tests/protocols/2026-09-12-wirkungsnachweise-0.29.0.md +121 -0
  497. package/.koolie/core/tests/protocols/2026-09-12-wirkungsnachweise-0.30.0.md +112 -0
  498. package/.koolie/core/tests/protocols/2026-09-12-wirkungsnachweise-0.31.0.md +107 -0
  499. package/.koolie/core/tests/protocols/2026-09-13-B06-gegenpruefung.md +370 -0
  500. package/.koolie/core/tests/protocols/2026-09-13-B07-B09-gegenpruefung.md +211 -0
  501. package/.koolie/core/tests/protocols/2026-09-13-B08-B11-gegenpruefung.md +179 -0
  502. package/.koolie/core/tests/protocols/2026-09-13-erhebung-disallowed-tools.md +147 -0
  503. package/.koolie/core/tests/protocols/2026-09-13-erhebung-unteragent-tiefe.md +139 -0
  504. package/.koolie/core/tests/protocols/2026-09-13-erhebung-unteragent.md +214 -0
  505. package/.koolie/core/tests/protocols/2026-09-13-gegenpruefung-berechtigungsdatei.md +253 -0
  506. package/.koolie/core/tests/protocols/2026-09-13-gegenpruefung-stumme-brueche.md +202 -0
  507. package/.koolie/core/tests/protocols/2026-09-13-gegenpruefung-werkzeugabbildung.md +219 -0
  508. package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.32.0.md +133 -0
  509. package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.33.0.md +169 -0
  510. package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.34.0.md +187 -0
  511. package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.35.0.md +187 -0
  512. package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.36.0.md +137 -0
  513. package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.37.0.md +112 -0
  514. package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.38.0.md +154 -0
  515. package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.39.0.md +188 -0
  516. package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.40.0.md +214 -0
  517. package/.koolie/core/tests/protocols/2026-09-14-erhebung-devin-werkzeuge.md +267 -0
  518. package/.koolie/core/tests/protocols/2026-09-14-erhebung-skillaufruf.md +238 -0
  519. package/.koolie/core/tests/protocols/2026-09-14-gegenpruefung-pruefregister.md +156 -0
  520. package/.koolie/core/tests/protocols/2026-09-14-gegenpruefung-schlitzdeckung.md +206 -0
  521. package/.koolie/core/tests/protocols/2026-09-14-gegenpruefung-skillwahl.md +127 -0
  522. package/.koolie/core/tests/protocols/2026-09-14-migrationslauf-pilot.md +134 -0
  523. package/.koolie/core/tests/protocols/2026-09-14-wirkungsnachweise-0.41.0.md +175 -0
  524. package/.koolie/core/tests/protocols/2026-09-14-wirkungsnachweise-0.42.0.md +180 -0
  525. package/.koolie/core/tests/protocols/2026-09-14-wirkungsnachweise-0.43.0.md +165 -0
  526. package/.koolie/core/tests/protocols/2026-09-14-wirkungsnachweise-0.44.0.md +130 -0
  527. package/.koolie/core/tests/protocols/2026-09-15-gegenpruefung-d11-zaehlregeln.md +311 -0
  528. package/.koolie/core/tests/protocols/2026-09-15-gegenpruefung-modulstatus.md +524 -0
  529. package/.koolie/core/tests/protocols/2026-09-15-gegenpruefung-nicht-skill-traeger.md +225 -0
  530. package/.koolie/core/tests/protocols/2026-09-15-gegenpruefung-restliche-nicht-skill-traeger.md +345 -0
  531. package/.koolie/core/tests/protocols/2026-09-15-gegenpruefung-strukturentscheidungen.md +392 -0
  532. package/.koolie/core/tests/protocols/2026-09-15-herrichtung-uebungsrepositorium.md +213 -0
  533. package/.koolie/core/tests/protocols/2026-09-15-migrationslauf-pilot-0.46.0.md +143 -0
  534. package/.koolie/core/tests/protocols/2026-09-15-wirkungsnachweise-0.45.0.md +127 -0
  535. package/.koolie/core/tests/protocols/2026-09-15-wirkungsnachweise-0.46.0.md +193 -0
  536. package/.koolie/core/tests/protocols/2026-09-15-wirkungsnachweise-0.47.0.md +149 -0
  537. package/.koolie/core/tests/protocols/2026-09-15-wirkungsnachweise-0.49.0.md +202 -0
  538. package/.koolie/core/tests/protocols/2026-09-15-wirkungsnachweise-0.50.0.md +183 -0
  539. package/.koolie/core/tests/protocols/2026-09-15-wirkungsnachweise-0.51.0.md +202 -0
  540. package/.koolie/core/tests/protocols/2026-09-15-wirkungsnachweise-0.52.0.md +168 -0
  541. package/.koolie/core/tests/protocols/2026-09-16-AP2-zielversion-devin-desktop.md +231 -0
  542. package/.koolie/core/tests/protocols/2026-09-16-wirkungsnachweise-0.53.0.md +350 -0
  543. package/.koolie/core/tests/protocols/2026-09-17-nachtrag-migrationshinweis-0.54.1.md +121 -0
  544. package/.koolie/core/tests/protocols/2026-09-17-sitzungstest-pi-ds.md +523 -0
  545. package/.koolie/core/tests/protocols/2026-09-17-sitzungstest-schranken.md +433 -0
  546. package/.koolie/core/tests/protocols/2026-09-17-wirkungsnachweise-0.54.0.md +159 -0
  547. package/.koolie/core/tests/protocols/2026-09-18-FW-AK-01.md +442 -0
  548. package/.koolie/core/tests/protocols/2026-09-18-FW-KO-05.md +231 -0
  549. package/.koolie/core/tests/protocols/2026-09-18-herrichtung-uebungsrepositorium.md +273 -0
  550. package/.koolie/core/tests/protocols/2026-09-18-nachtrag-preis-umbenennung-0.56.1.md +102 -0
  551. package/.koolie/core/tests/protocols/2026-09-18-sitzungstest-5.md +349 -0
  552. package/.koolie/core/tests/protocols/2026-09-18-sitzungstest-ne-sc.md +430 -0
  553. package/.koolie/core/tests/protocols/2026-09-18-sitzungstest-pi-ds-2.md +499 -0
  554. package/.koolie/core/tests/protocols/2026-09-18-vorbedingungen-sitzungstest-5-zweiter-durchgang.md +170 -0
  555. package/.koolie/core/tests/protocols/2026-09-18-vorbedingungen-testblaetter.md +184 -0
  556. package/.koolie/core/tests/protocols/2026-09-18-wirkungsnachweise-0.55.0.md +202 -0
  557. package/.koolie/core/tests/protocols/2026-09-18-wirkungsnachweise-0.56.0.md +135 -0
  558. package/.koolie/core/tests/protocols/2026-09-18-wirkungsnachweise-0.56.2.md +154 -0
  559. package/.koolie/core/tests/protocols/2026-09-18-wirkungsnachweise-0.57.0.md +228 -0
  560. package/.koolie/core/tests/protocols/2026-09-18-wirkungsnachweise-0.57.1.md +262 -0
  561. package/.koolie/core/tests/protocols/2026-09-18-wirkungsnachweise-0.58.0.md +135 -0
  562. package/.koolie/core/tests/protocols/2026-09-18-wirkungsnachweise-0.59.0.md +150 -0
  563. package/.koolie/core/tests/protocols/2026-09-18-wirkungsnachweise-0.60.0.md +340 -0
  564. package/.koolie/core/tests/protocols/2026-09-19-herrichtung-buendel-4.md +235 -0
  565. package/.koolie/core/tests/protocols/2026-09-19-k77-zurechenbarkeit.md +236 -0
  566. package/.koolie/core/tests/protocols/2026-09-19-pruefapparat-filter.md +50 -0
  567. package/.koolie/core/tests/protocols/2026-09-19-pruefmittelwort-und-buendelschnitt.md +239 -0
  568. package/.koolie/core/tests/protocols/2026-09-19-sechzehnte-praeparation.md +135 -0
  569. package/.koolie/core/tests/protocols/2026-09-19-testblaetter-buendel-1.md +250 -0
  570. package/.koolie/core/tests/protocols/2026-09-19-testblaetter-buendel-2.md +229 -0
  571. package/.koolie/core/tests/protocols/2026-09-19-testblaetter-buendel-3.md +293 -0
  572. package/.koolie/core/tests/protocols/2026-09-19-vorbedingungen-buendel-2.md +236 -0
  573. package/.koolie/core/tests/protocols/2026-09-19-vorbedingungen-buendel-3.md +253 -0
  574. package/.koolie/core/tests/protocols/2026-09-19-vorbedingungen-buendel-4.md +138 -0
  575. package/.koolie/core/tests/protocols/2026-09-20-messapparat-buendel-4.md +433 -0
  576. package/.koolie/core/tests/protocols/2026-09-20-testblaetter-buendel-4.md +321 -0
  577. package/.koolie/core/tests/protocols/2026-09-20-uebergabe-im-release-commit.md +146 -0
  578. package/.koolie/core/tests/protocols/2026-09-20-vorbedingungen-nachlauf-b4.md +259 -0
  579. package/.koolie/core/tests/protocols/2026-09-21-arbeitsplatz-im-kern.md +127 -0
  580. package/.koolie/core/tests/protocols/2026-09-21-nachlauf-buendel-4.md +157 -0
  581. package/.koolie/core/tests/protocols/2026-09-21-vorbedingungen-buendel-5.md +247 -0
  582. package/.koolie/core/tests/protocols/2026-09-21-wiederaufnahme-nachlauf-b4.md +190 -0
  583. package/.koolie/core/tests/protocols/2026-09-22-ap2-rest-devin-desktop.md +614 -0
  584. package/.koolie/core/tests/protocols/2026-09-22-hauptdokument-ap11.md +443 -0
  585. package/.koolie/core/tests/protocols/2026-09-22-herrichtung-buendel-5.md +224 -0
  586. package/.koolie/core/tests/protocols/2026-09-22-messtag-buendel-5.md +327 -0
  587. package/.koolie/core/tests/protocols/2026-09-22-quellenzuordnung-matrixzeilen.md +230 -0
  588. package/.koolie/core/tests/protocols/2026-09-22-sammelzellen-zentraler-katalog.md +354 -0
  589. package/.koolie/core/tests/protocols/2026-09-22-umbenennung-koolie.md +296 -0
  590. package/.koolie/core/tests/protocols/2026-09-22-verify-marker-abschaffen.md +283 -0
  591. package/.koolie/core/tests/protocols/2026-09-22-vortrag-und-name.md +261 -0
  592. package/.koolie/core/tests/protocols/2026-09-22-wirkungsnachweise-0.86.0.md +158 -0
  593. package/.koolie/core/tests/protocols/2026-09-23-archiv-zeilenenden.md +113 -0
  594. package/.koolie/core/tests/protocols/2026-09-23-bau-openai-codex.md +168 -0
  595. package/.koolie/core/tests/protocols/2026-09-23-chronik-und-vorlage.md +224 -0
  596. package/.koolie/core/tests/protocols/2026-09-23-erhebung-openai-codex.md +309 -0
  597. package/.koolie/core/tests/protocols/2026-09-23-freigabelauf-1.0.0-vorbereitung.md +119 -0
  598. package/.koolie/core/tests/protocols/2026-09-23-freigabelauf-1.0.0.md +150 -0
  599. package/.koolie/core/tests/protocols/2026-09-23-gegenzeichnung-rollenfrage.md +198 -0
  600. package/.koolie/core/tests/protocols/2026-09-23-reihenfolge-des-hebens.md +220 -0
  601. package/.koolie/core/tests/protocols/2026-09-23-word-fassung-und-blinder-fleck.md +307 -0
  602. package/.koolie/core/tests/protocols/2026-09-24-kopierweg-kern.md +98 -0
  603. package/.koolie/core/tests/protocols/2026-09-24-overlay-werte-einordnung.md +111 -0
  604. package/.koolie/core/tests/protocols/2026-09-24-pfadlisten-nul-getrennt.md +128 -0
  605. package/.koolie/core/tests/protocols/2026-09-24-uebergabe-lokal.md +85 -0
  606. package/.koolie/core/tests/protocols/2026-09-25-code-pack-posten.md +86 -0
  607. package/.koolie/core/tests/protocols/2026-09-25-dokumentationsstandard.md +101 -0
  608. package/.koolie/core/tests/protocols/2026-09-25-installer-je-zielsystem.md +134 -0
  609. package/.koolie/core/tests/protocols/2026-09-25-klasse-b-core-laufzeit.md +126 -0
  610. package/.koolie/core/tests/protocols/2026-09-25-klasse-b-governance.md +133 -0
  611. package/.koolie/core/tests/protocols/2026-09-25-klasse-b-skills.md +91 -0
  612. package/.koolie/core/tests/protocols/2026-09-25-lieferumfang.md +76 -0
  613. package/.koolie/core/tests/protocols/2026-09-25-overlay-muster-dokumente.md +107 -0
  614. package/.koolie/core/tests/protocols/2026-09-25-overlay-muster-general.md +100 -0
  615. package/.koolie/core/tests/protocols/2026-09-25-regel-register-posten.md +87 -0
  616. package/.koolie/core/tests/protocols/2026-09-26-attributionszeile.md +83 -0
  617. package/.koolie/core/tests/protocols/2026-09-26-auffindbarkeit.md +85 -0
  618. package/.koolie/core/tests/protocols/2026-09-26-bau-cursor.md +68 -0
  619. package/.koolie/core/tests/protocols/2026-09-26-bau-kiro.md +75 -0
  620. package/.koolie/core/tests/protocols/2026-09-26-mehrprojekt-tokenlast.md +174 -0
  621. package/.koolie/core/tests/protocols/2026-09-26-regelablage-pfadtoken.md +133 -0
  622. package/.koolie/core/tests/protocols/2026-09-26-skill-anweisungen.md +111 -0
  623. package/.koolie/core/tests/protocols/2026-09-26-testblaetter-modellwechsel.md +106 -0
  624. package/.koolie/core/tests/protocols/2026-09-27-mandat-und-reibung.md +58 -0
  625. package/.koolie/core/tests/protocols/2026-09-28-mcp-anbindung.md +72 -0
  626. package/.koolie/core/tests/protocols/2026-09-29-messapparat.md +75 -0
  627. package/.koolie/core/tests/protocols/2026-09-29-powershell.md +58 -0
  628. package/.koolie/core/tests/protocols/2026-09-29-pruefwerkzeuge.md +64 -0
  629. package/.koolie/core/tests/protocols/2026-09-29-registerpflege.md +228 -0
  630. package/.koolie/core/tests/protocols/2026-09-29-schutzschicht.md +95 -0
  631. package/.koolie/core/tests/protocols/2026-09-30-einsatzarchitektur.md +104 -0
  632. package/.koolie/core/tests/protocols/2026-09-30-modi-ausnahmen.md +77 -0
  633. package/.koolie/core/tests/protocols/2026-09-30-nachlauf-banner.md +85 -0
  634. package/.koolie/core/tests/protocols/2026-09-30-paketquellen.md +65 -0
  635. package/.koolie/core/tests/protocols/2026-09-30-pfadsemantik.md +79 -0
  636. package/.koolie/core/tests/protocols/2026-10-01-auftritt-und-suche.md +58 -0
  637. package/.koolie/core/tests/protocols/2026-10-01-befehl-im-projektverzeichnis.md +47 -0
  638. package/.koolie/core/tests/protocols/2026-10-01-erste-veroeffentlichung.md +60 -0
  639. package/.koolie/core/tests/protocols/2026-10-01-modusbindung-messfragen.md +107 -0
  640. package/.koolie/core/tests/protocols/README.md +14 -0
  641. package/.koolie/core/tests/scripts/hook-check-secrets.py +1307 -0
  642. package/.koolie/core/tests/scripts/hook-overlay-status.py +120 -0
  643. package/.koolie/core/tests/scripts/mermaid_renderer.py +67 -0
  644. package/.koolie/core/tests/scripts/overlay_status.py +130 -0
  645. package/.koolie/core/tests/scripts/probe-pruefungen.py +110 -0
  646. package/.koolie/core/tests/scripts/pruefungen/__init__.py +4 -0
  647. package/.koolie/core/tests/scripts/pruefungen/berechtigungen.py +1559 -0
  648. package/.koolie/core/tests/scripts/pruefungen/bestand.py +1433 -0
  649. package/.koolie/core/tests/scripts/pruefungen/dokumente.py +1262 -0
  650. package/.koolie/core/tests/scripts/pruefungen/gemeinsam.py +784 -0
  651. package/.koolie/core/tests/scripts/pruefungen/hooks.py +1188 -0
  652. package/.koolie/core/tests/scripts/pruefungen/overlay.py +1251 -0
  653. package/.koolie/core/tests/scripts/pruefungen/packs.py +1314 -0
  654. package/.koolie/core/tests/scripts/pruefungen/register.py +950 -0
  655. package/.koolie/core/tests/scripts/pruefungen/testkatalog.py +1202 -0
  656. package/.koolie/core/tests/scripts/pruefungen/werkzeuge.py +957 -0
  657. package/.koolie/core/tests/scripts/sonden/__init__.py +4 -0
  658. package/.koolie/core/tests/scripts/sonden/apparat.py +653 -0
  659. package/.koolie/core/tests/scripts/sonden/teil01_grundbestand_und_installation.py +999 -0
  660. package/.koolie/core/tests/scripts/sonden/teil02_packs_mandat_mcp.py +942 -0
  661. package/.koolie/core/tests/scripts/sonden/teil03_pruefungen_26_bis_36.py +1184 -0
  662. package/.koolie/core/tests/scripts/sonden/teil04_pruefungen_37_bis_45.py +1491 -0
  663. package/.koolie/core/tests/scripts/sonden/teil05_pruefungen_46_bis_55.py +1447 -0
  664. package/.koolie/core/tests/scripts/sonden/teil06_pruefungen_57_bis_65.py +739 -0
  665. package/.koolie/core/tests/scripts/sonden/teil07_overlay_und_lieferung.py +1014 -0
  666. package/.koolie/core/tests/scripts/sonden/teil08_pruefungen_66_bis_80.py +1325 -0
  667. package/.koolie/core/tests/scripts/sonden/teil09_pruefmittel_81_und_82.py +505 -0
  668. package/.koolie/core/tests/scripts/sonden/teil10_pruefungen_83_bis_95.py +1218 -0
  669. package/.koolie/core/tests/scripts/sonden/teil11_pruefungen_104_und_105.py +149 -0
  670. package/.koolie/core/tests/scripts/sonden/teil12_pruefungen_106_und_107.py +136 -0
  671. package/.koolie/core/tests/scripts/sonden/teil13_pfad_und_mustersemantik.py +150 -0
  672. package/.koolie/core/tests/scripts/sonden/teil14_modi_ausnahmen_skills.py +204 -0
  673. package/.koolie/core/tests/scripts/sonden/teil15_banner_und_nachlauf.py +193 -0
  674. package/.koolie/core/tests/scripts/sonden/teil16_koexistenz.py +114 -0
  675. package/.koolie/core/tests/scripts/sonden/teil17_paketquellen.py +115 -0
  676. package/.koolie/core/tests/scripts/sonden/teil18_modusbindung_m3_m5.py +113 -0
  677. package/.koolie/core/tests/scripts/validate-framework.py +1104 -0
  678. package/.koolie/core/tests/scripts/validate-output.py +296 -0
  679. package/.koolie/core/wirksamkeit.py +430 -0
  680. package/CONTRIBUTING.md +119 -0
  681. package/LICENSE +674 -0
  682. package/QUICKSTART.en.md +135 -0
  683. package/QUICKSTART.md +129 -0
  684. package/README.en.md +108 -0
  685. package/README.md +107 -0
  686. package/install.cmd +44 -0
  687. package/install.command +46 -0
  688. package/package.json +21 -0
  689. package/paketquellen/README.md +41 -0
  690. package/paketquellen/bauen.py +411 -0
  691. package/paketquellen/koolie.cmd +23 -0
  692. package/paketquellen/koolie_befehl.py +82 -0
  693. package/paketquellen/npm/koolie.js +26 -0
@@ -0,0 +1,1491 @@
1
+ """Sonden zu den Pruefungen 37 bis 45 und zum Bytecode; Selbstprobe des Aufraeumers.
2
+
3
+ Teil des Sondenskripts probe-pruefungen.py, seit 1.19.1 in Module geteilt (K-174). Die
4
+ Einheiten melden sich beim Laden dieses Moduls an; der Einstieg laedt die Module in der
5
+ Reihenfolge ihrer Nummer, und das ist die Reihenfolge der Ausgabe (D-49). Ein Modul
6
+ liest nur aus dem Apparat und aus frueheren Teilen."""
7
+ from __future__ import annotations
8
+
9
+ import io
10
+ import json
11
+ import os
12
+ import re
13
+ import shutil
14
+ import stat
15
+ import tempfile
16
+
17
+ from .apparat import (
18
+ _ORT, _p, aufraeumen, buendel, Einheit, ersetze, ersetzt, frei, gegenprobe,
19
+ installation, lies, melde, notiz, P, Praeparationsfehler, schreib,
20
+ schreibschutz_loesen, sonde, unterprozess, validator_ausgabe, zeile_nach)
21
+
22
+
23
+ # --- Selbstprobe: der Aufraeumer (CR-2026-068, D-96) ------------------------------
24
+ #
25
+ # Ohne sie waere der Aufraeumer eine ungepruefte Zusage - und zwar ausgerechnet die, die
26
+ # an die Stelle von ignore_errors=True getreten ist. Eine Meldung, die geschrieben und
27
+ # nie ausgeloest wurde, ist nach D-23 nicht vorhanden.
28
+ #
29
+ # GEMESSEN WIRD GEGEN EINE HILFSEINHEIT, nicht gegen die laufende: Der Aufraeumer meldet
30
+ # in die Einheit, in der er gerufen wird. Taete er das hier, zaehlte sein absichtlich
31
+ # herbeigefuehrter Ausfall als Abweichung des Laufs - die Selbstprobe erzeugte den Befund,
32
+ # den sie misst.
33
+
34
+ def _mit_zeuge(zeuge, tun) -> None:
35
+ """`tun` so ausfuehren, dass alle Meldungen in `zeuge` landen, nicht im Lauf."""
36
+ eigene = _ORT.einheit
37
+ _ORT.einheit = zeuge
38
+ try:
39
+ tun()
40
+ finally:
41
+ _ORT.einheit = eigene
42
+
43
+
44
+ def _zeuge(nummer: str):
45
+ return Einheit("SELBSTPROBE", nummer,
46
+ "Hilfseinheit der Selbstprobe %s - sie wird nie angemeldet und "
47
+ "erscheint in keinem Lauf" % nummer, lambda: None)
48
+
49
+
50
+ def _festhalten(ziel: str):
51
+ """Ein Arbeitsverzeichnis gegen das Loeschen sperren - je Betriebssystem anders.
52
+
53
+ Unter Windows genuegt eine offene Datei darin: das Entfernen scheitert mit
54
+ WinError 32. Unter POSIX nicht - dort haengt das Loeschen einer Datei am
55
+ Schreibrecht ihres VERZEICHNISSES, also wird dieses entzogen. **Ohne diese
56
+ Unterscheidung waere die Selbstprobe auf einem der beiden Systeme eine Zeile, die
57
+ nichts misst** - und genau dagegen ist sie gebaut.
58
+ """
59
+ innen = os.path.join(ziel, "unterordner")
60
+ os.makedirs(innen)
61
+ pfad = os.path.join(innen, "gehalten.txt")
62
+ schreib(pfad, "Diese Datei haelt ihr Verzeichnis fest.\r\n")
63
+ if os.name == "nt":
64
+ return io.open(pfad, "r+", encoding="utf-8")
65
+ os.chmod(innen, 0o500)
66
+ return innen
67
+
68
+
69
+ def _loslassen(halter) -> None:
70
+ if hasattr(halter, "close"):
71
+ halter.close()
72
+ else:
73
+ os.chmod(halter, 0o700)
74
+
75
+
76
+ def selbstprobe_aufraeumer() -> None:
77
+ """Der Aufraeumer schweigt, wenn er seine Arbeit tut, und meldet, wenn nicht."""
78
+ ziel = tempfile.mkdtemp(prefix="lw-auf-")
79
+ schreib(os.path.join(ziel, "datei.txt"), "Sondendatei\r\n")
80
+ zeuge = _zeuge("A1")
81
+ _mit_zeuge(zeuge, lambda: aufraeumen(ziel))
82
+ melde("SELBSTPROBE", "A1", not os.path.isdir(ziel) and not zeuge.zeilen,
83
+ "Ein geloeschtes Arbeitsverzeichnis erzeugt keine Zeile - der Aufraeumer "
84
+ "schweigt, wenn er seine Arbeit tut")
85
+
86
+ # --- A3: der Schreibschutz, und er ist kein gedachter Fall -----------------------
87
+ # Gemessen am 2026-09-15: git schreibt seine Objektdateien schreibgeschuetzt, und
88
+ # drei Versuche ueber anderthalb Sekunden endeten dreimal mit demselben
89
+ # "Zugriff verweigert". Warten hilft dagegen nicht.
90
+ #
91
+ # Unter POSIX blockiert eine schreibgeschuetzte DATEI das Loeschen nicht - dort
92
+ # haengt es am Schreibrecht ihres Verzeichnisses. Die Probe gilt trotzdem auf
93
+ # beiden Systemen, nur aus verschiedenen Gruenden: Unter Windows belegt sie den
94
+ # Mechanismus, unter POSIX, dass er nichts kaputt macht. **Wer ihn unter Windows
95
+ # entfernt, macht sie rot** - und das ist ihr Zweck.
96
+ ziel = tempfile.mkdtemp(prefix="lw-auf-")
97
+ pfad = os.path.join(ziel, "schreibgeschuetzt.txt")
98
+ schreib(pfad, "Diese Datei ist schreibgeschuetzt.\r\n")
99
+ os.chmod(pfad, stat.S_IREAD)
100
+ zeuge = _zeuge("A3")
101
+ _mit_zeuge(zeuge, lambda: aufraeumen(ziel))
102
+ melde("SELBSTPROBE", "A3", not os.path.isdir(ziel) and not zeuge.zeilen,
103
+ "Eine schreibgeschuetzte Datei haelt das Arbeitsverzeichnis nicht fest - der "
104
+ "Aufraeumer nimmt den Schutz weg und schweigt")
105
+ if os.path.isdir(ziel):
106
+ notiz(" Gesammelt wurde:", " | ".join(zeuge.zeilen) or "nichts")
107
+ schreibschutz_loesen(ziel)
108
+ shutil.rmtree(ziel, ignore_errors=True)
109
+
110
+ ziel = tempfile.mkdtemp(prefix="lw-auf-")
111
+ halter = _festhalten(ziel)
112
+ try:
113
+ zeuge = _zeuge("A2")
114
+ _mit_zeuge(zeuge, lambda: aufraeumen(ziel))
115
+ gemeldet = zeuge.fehler == 1 and any("bleibt liegen" in z for z in zeuge.zeilen)
116
+ genannt = any(ziel in z for z in zeuge.zeilen)
117
+ ok = os.path.isdir(ziel) and gemeldet and genannt
118
+ melde("SELBSTPROBE", "A2", ok,
119
+ "Ein Verzeichnis, das sich nicht loeschen laesst, wird mit Pfad und Grund "
120
+ "gemeldet und zaehlt als Abweichung")
121
+ if not ok:
122
+ notiz(" Gesammelt wurde:", " | ".join(zeuge.zeilen) or "nichts")
123
+ finally:
124
+ _loslassen(halter)
125
+ aufraeumen(ziel)
126
+
127
+
128
+ buendel(selbstprobe_aufraeumer,
129
+ "Der Aufraeumer schweigt beim Gelingen und meldet sein Scheitern mit Pfad und "
130
+ "Grund - gemessen an einem Verzeichnis, das sich nicht loeschen laesst")
131
+
132
+
133
+ # --- 37: Die drei Koerbe der Berechtigungsdatei gegen die Kernquelle (D-77) --------
134
+ #
135
+ # GEGEN EINE ECHTE INSTALLATION, aus demselben Grund wie bei Pruefung 33: Der Gegenstand
136
+ # ist eine installierte Datei, nicht ein Text des Repositoriums. Eine Sonde auf einer
137
+ # Kopie des Repositoriums traefe die Testinstallation des Packs devin-desktop und damit
138
+ # nur eine der beiden Abbildungen - und der Praefixteil der Pruefung hat dort seinen
139
+ # Gegenstand gar nicht (permission_exec_match: literal).
140
+ #
141
+ # Anlass sind zwoelf Messungen vom 2026-09-13 (CR-2026-061): Acht Eingriffe in die Datei
142
+ # liefen gegen 0.38.0 ohne eine einzige Meldung durch, darunter das Loeschen ALLER 41
143
+ # Nicht-Kernregeln des deny-Korbs.
144
+ #
145
+ # Die erste Gegenprobe ist hier die wichtigere Haelfte, und zwar in zwei Zuschnitten:
146
+ # im Auslieferungszustand mit offenen Platzhaltern und mit ordentlich gefuellten. Eine
147
+ # Pruefung, die jede gefuellte Datei beanstandet, bestuende jede Sonde.
148
+ def _p37(root: str) -> str:
149
+ return os.path.join(root, ".claude", "settings.json")
150
+
151
+
152
+ def _37_korb(daten: dict, korb: str) -> list:
153
+ return daten.setdefault("permissions", {}).setdefault(korb, [])
154
+
155
+
156
+ def _37_weg(daten: dict, korb: str, regel: str) -> None:
157
+ """Eine Regel entfernen - sie muss vorher dastehen."""
158
+ regeln = _37_korb(daten, korb)
159
+ if regel not in regeln:
160
+ raise Praeparationsfehler(
161
+ "settings.json: %r steht nicht im %s-Korb; die Sonde hat ihren Gegenstand "
162
+ "verloren" % (regel, korb))
163
+ regeln.remove(regel)
164
+
165
+
166
+ def _37_dazu(daten: dict, korb: str, regel: str) -> None:
167
+ """Eine Regel ergaenzen - sie darf vorher nicht dastehen, sonst misst die Sonde nichts."""
168
+ regeln = _37_korb(daten, korb)
169
+ if regel in regeln:
170
+ raise Praeparationsfehler(
171
+ "settings.json: %r steht bereits im %s-Korb; die Sonde praepariert nichts"
172
+ % (regel, korb))
173
+ regeln.append(regel)
174
+
175
+
176
+ def _37_statt(daten: dict, korb: str, alt: str, neu: str) -> None:
177
+ regeln = _37_korb(daten, korb)
178
+ if alt not in regeln:
179
+ raise Praeparationsfehler(
180
+ "settings.json: %r steht nicht im %s-Korb; die Sonde hat ihren Gegenstand "
181
+ "verloren" % (alt, korb))
182
+ regeln[regeln.index(alt)] = neu
183
+
184
+
185
+ def _37_schreiben(root: str, *aenderungen) -> None:
186
+ """Die Eingriffe anwenden und die Datei schreiben.
187
+
188
+ Der Praeparationswaechter sitzt in den Eingriffen selbst (_37_weg, _37_dazu,
189
+ _37_statt): Sie pruefen ihren Gegenstand, statt ihn vorauszusetzen. Ein Textvergleich
190
+ vorher/nachher taugte hier nicht - json.dumps normalisiert die Datei ohnehin, und der
191
+ Waechter meldete dann immer "veraendert" (D-74).
192
+ """
193
+ pfad = _p37(root)
194
+ daten = json.loads(lies(pfad))
195
+ for aenderung in aenderungen:
196
+ aenderung(daten)
197
+ schreib(pfad, json.dumps(daten, indent=2, ensure_ascii=False) + "\n")
198
+
199
+
200
+ MELDUNG_FEHLT = "die Kernquelle erzeugt f\u00fcr den"
201
+ MELDUNG_ZUVIEL = "die die Kernquelle nicht erzeugt"
202
+ MELDUNG_PRAEFIX = "tr\u00e4gt das Pr\u00e4fixzeichen"
203
+
204
+
205
+ def sonden_berechtigungskoerbe() -> None:
206
+ """Wirkungsnachweis zu Pruefung 37 (CR-2026-061, D-76 und D-77)."""
207
+ root = installation("claude-code")
208
+ try:
209
+ pfad = _p37(root)
210
+ ausgang = lies(pfad)
211
+ # README.md ist Pflichtpfad; ohne sie meldet jeder Lauf zwei Fehler, die mit
212
+ # dieser Pruefung nichts zu tun haben.
213
+ schreib(os.path.join(root, "README.md"), "# Sondenprojekt\r\n")
214
+
215
+ # --- Gegenprobe 37a: der Auslieferungszustand bleibt unbeanstandet ----------
216
+ aus = validator_ausgabe(root)
217
+ ok = (MELDUNG_FEHLT not in aus and MELDUNG_ZUVIEL not in aus
218
+ and MELDUNG_PRAEFIX not in aus)
219
+ melde("GEGENPROBE", "37a", ok,
220
+ "Auslieferungszustand mit offenen Platzhaltern - ein Schlitz ist ein Schlitz")
221
+ if not ok:
222
+ notiz(" Ausgabe:", " | ".join(
223
+ z for z in aus.splitlines() if "settings.json" in z)[:400])
224
+
225
+ # --- Gegenprobe 37b: ordentlich gefuellte Platzhalter bleiben unbeanstandet -
226
+ # Ohne sie stuende nur fest, dass die Pruefung irgendetwas meldet - und eine
227
+ # Pruefung, die jede gefuellte Datei beanstandet, bestuende jede Sonde.
228
+ _37_schreiben(root,
229
+ lambda d: _37_statt(d, "ask", "Bash(<BUILD_COMMAND>)",
230
+ "Bash(mvn -B clean package)"),
231
+ lambda d: _37_statt(d, "ask", "Bash(<TEST_COMMAND>)",
232
+ "Bash(mvn -B test)"),
233
+ lambda d: _37_statt(d, "ask", "Bash(<LINT_COMMAND>)",
234
+ "Bash(mvn -B verify)"))
235
+ aus = validator_ausgabe(root)
236
+ ok = (MELDUNG_FEHLT not in aus and MELDUNG_ZUVIEL not in aus
237
+ and MELDUNG_PRAEFIX not in aus)
238
+ melde("GEGENPROBE", "37b", ok,
239
+ "Drei gefuellte Befehlsschlitze ohne Praefixzeichen - der Normalfall")
240
+ if not ok:
241
+ notiz(" Ausgabe:", " | ".join(
242
+ z for z in aus.splitlines() if "settings.json" in z)[:400])
243
+ schreib(pfad, ausgang)
244
+
245
+ # --- 37a: eine NICHT-Kernregel aus deny geloescht ---------------------------
246
+ # 41 der 54 deny-Regeln standen bis 0.38.0 ausserhalb jeder Pruefung.
247
+ _37_schreiben(root, lambda d: _37_weg(d, "deny", "Bash(curl:*)"))
248
+ aus = validator_ausgabe(root)
249
+ melde("SONDE", "37a", MELDUNG_FEHLT in aus,
250
+ "Geloeschte Nicht-Kernregel im deny-Korb - bis 0.38.0 stumm")
251
+ schreib(pfad, ausgang)
252
+
253
+ # --- 37b: eine Nicht-Kernregel VERENGT --------------------------------------
254
+ # Die stillste Form: Sie sieht aus wie eine Regel und sperrt weniger.
255
+ _37_schreiben(root, lambda d: _37_statt(d, "deny", "Bash(kubectl:*)",
256
+ "Bash(kubectl delete:*)"))
257
+ aus = validator_ausgabe(root)
258
+ melde("SONDE", "37b", MELDUNG_FEHLT in aus,
259
+ "Verengte Nicht-Kernregel - kubectl apply liefe wieder")
260
+ schreib(pfad, ausgang)
261
+
262
+ # --- 37c: eine Zeile im ask-Korb ergaenzt -----------------------------------
263
+ # Der Fall CR-OTP-G-001: Die Zeile erklaert einen Befehl fuer freigegeben.
264
+ _37_schreiben(root, lambda d: _37_dazu(
265
+ d, "ask", "Bash(docker run --rm --network none:*)"))
266
+ aus = validator_ausgabe(root)
267
+ melde("SONDE", "37c", MELDUNG_ZUVIEL in aus,
268
+ "Ergaenzte ask-Zeile - der Antrag CR-OTP-G-001 des Piloten")
269
+ schreib(pfad, ausgang)
270
+
271
+ # --- 37d: eine Zeile im allow-Korb ergaenzt ---------------------------------
272
+ _37_schreiben(root, lambda d: _37_dazu(d, "allow", "Bash(docker run:*)"))
273
+ aus = validator_ausgabe(root)
274
+ melde("SONDE", "37d", MELDUNG_ZUVIEL in aus,
275
+ "Ergaenzte allow-Zeile - kein Abrufwerkzeug, nicht auf der Verbotsliste")
276
+ schreib(pfad, ausgang)
277
+
278
+ # --- 37e: der ask-Korb geleert ----------------------------------------------
279
+ _37_schreiben(root, lambda d: d["permissions"].__setitem__("ask", []))
280
+ aus = validator_ausgabe(root)
281
+ melde("SONDE", "37e", MELDUNG_FEHLT in aus,
282
+ "Geleerter ask-Korb - Edit(**) und mcp__* verschwinden mit")
283
+ schreib(pfad, ausgang)
284
+
285
+ # --- 37f: ein Befehlsschlitz mit Praefixzeichen gefuellt --------------------
286
+ # Am Piloten am 2026-09-13 so vorgefunden: Bash(mvn -B test:*).
287
+ _37_schreiben(root, lambda d: _37_statt(d, "ask", "Bash(<TEST_COMMAND>)",
288
+ "Bash(mvn -B test:*)"))
289
+ aus = validator_ausgabe(root)
290
+ melde("SONDE", "37f", MELDUNG_PRAEFIX in aus,
291
+ "Befehlsschlitz mit Praefixzeichen gefuellt - der Fall des Piloten")
292
+ schreib(pfad, ausgang)
293
+
294
+ # --- 37h und Gegenprobe 37c: die Skillfreigabe eines aktivierten Packs ----
295
+ #
296
+ # 🔴 ZWEI PRUEFUNGEN DESSELBEN REPOSITORIUMS STANDEN GEGENEINANDER
297
+ # (2026-09-21, D-243). Pruefung 72 verlangt seit `0.81.0` zu jedem Skill der
298
+ # Installation einen Korbeintrag - der dritte Teil der Aktivierung eines
299
+ # Packs (D-238). Pruefung 37 hielt genau diesen Eintrag fuer eine Ausweitung,
300
+ # weil die Kernquelle ihn nicht erzeugt. Damit war D-238 in keinem Projekt
301
+ # umsetzbar, ohne den eigenen Validator rot zu faerben.
302
+ #
303
+ # Das PAAR belegt den Zuschnitt: Ein Eintrag auf einen Skill, der in der
304
+ # Ablage liegt, ist keine Ausweitung; derselbe Eintrag auf einen Namen ohne
305
+ # Skill bleibt einer.
306
+ skillablage = os.path.join(root, ".claude", "skills")
307
+ quelle = os.path.join(root, ".koolie/core", "framework", "role-packs",
308
+ "requirements-engineering", "skills", "role-re-ticket")
309
+ shutil.copytree(quelle, os.path.join(skillablage, "role-re-ticket"))
310
+ _37_schreiben(root, lambda d: _37_dazu(d, "allow", "Skill(role-re-ticket)"))
311
+ aus = validator_ausgabe(root)
312
+ melde("GEGENPROBE", "37c", MELDUNG_ZUVIEL not in aus,
313
+ "Vollstaendig aktiviertes Role Pack - Skill in der Ablage UND im Korb, "
314
+ "und Pruefung 37 schweigt dazu")
315
+ if MELDUNG_ZUVIEL in aus:
316
+ notiz(" Ausgabe:", " | ".join(
317
+ z for z in aus.splitlines() if "settings.json" in z)[:400])
318
+ schreib(pfad, ausgang)
319
+
320
+ _37_schreiben(root, lambda d: _37_dazu(d, "allow", "Skill(role-gibt-es-nicht)"))
321
+ aus = validator_ausgabe(root)
322
+ melde("SONDE", "37h", MELDUNG_ZUVIEL in aus,
323
+ "Dieselbe Schreibweise auf einen Namen ohne Skill in der Ablage bleibt "
324
+ "eine Ausweitung - der Zuschnitt haengt an der Ablage, nicht am Wort")
325
+ schreib(pfad, ausgang)
326
+ shutil.rmtree(os.path.join(skillablage, "role-re-ticket"))
327
+
328
+ # --- 37g: der verlorene Anker ----------------------------------------------
329
+ cm = os.path.join(root, ".koolie/core", "clientmap.py")
330
+ quelle = lies(cm)
331
+ schreib(cm, ersetzt(quelle, ("def basket_rules(", "def korb_regeln("),
332
+ quelle="clientmap.py"))
333
+ aus = validator_ausgabe(root)
334
+ melde("SONDE", "37g", "'basket_rules(' fehlt" in aus,
335
+ "Verlorener Anker - die Pruefung meldet ihr Fehlen selbst")
336
+ schreib(cm, quelle)
337
+ finally:
338
+ aufraeumen(os.path.dirname(root))
339
+
340
+
341
+ buendel(sonden_berechtigungskoerbe,
342
+ "Neun Eingriffe in die Berechtigungsdatei einer echten Installation, jeder einzeln "
343
+ "zurueckgesetzt: geloeschte, verengte und ergaenzte Regeln, geleerter ask-Korb, "
344
+ "Praefixzeichen und die Skillfreigabe eines aktivierten Packs")
345
+
346
+ # --- 38: Eine Quelle, ein Vokabular, eine Richtung (CR-2026-062, D-78 bis D-80) ----
347
+ #
348
+ # Auf einer Kopie des Repositoriums, nicht gegen eine Installation: Der Gegenstand von
349
+ # Pruefung 38 sind die Manifeste und die Quellen des Kerns, nicht eine erzeugte Datei.
350
+ # Das ist der Unterschied zu den Pruefungen 33 und 37.
351
+ #
352
+ # Acht Sonden, zwei Gegenproben. Die Sonden 38f und 38g treffen die beiden Stellen, an
353
+ # denen der Fall bis 0.39.0 STILL war: in allowed-tools wurde das unbekannte Verb
354
+ # woertlich als Werkzeugname durchgereicht, in permissions.deny fiel es lautlos aus.
355
+ MANIFEST_CC_38 = ".koolie/core/clients/claude-code/manifest.json"
356
+ MANIFEST_DD_38 = ".koolie/core/clients/devin-desktop/manifest.json"
357
+ SKILL_38 = ".koolie/core/framework/skills/fw-plan/SKILL.md"
358
+ CLIENTMAP_38 = ".koolie/core/clientmap.py"
359
+
360
+
361
+ def _38_json(root: str, rel: str, wandler) -> None:
362
+ """Ein Manifest ueber das JSON praeparieren, nicht ueber den Text.
363
+
364
+ Die beiden tool_names-Bloecke eines Manifests sind ZEICHENGLEICH; ein Textanker
365
+ traefe den falschen. Dieselbe Begruendung wie bei Sonde 35a.
366
+ """
367
+ pfad = P(root, rel.replace("/", os.sep))
368
+ daten = json.loads(lies(pfad))
369
+ wandler(daten)
370
+ schreib(pfad, json.dumps(daten, ensure_ascii=False, indent=2) + "\r\n")
371
+
372
+
373
+ def _38_deklaration_weg(root: str) -> None:
374
+ """Ein Verb faellt aus der Abbildung, ohne dass es erklaert wird.
375
+
376
+ Bis 0.42.0 hat diese Sonde die ERKLAERUNG entfernt; seit die Abbildung von
377
+ devin-desktop erhoben ist (D-87), gibt es keine mehr zu entfernen. Der Defekt ist
378
+ derselbe geblieben - er wird jetzt hergestellt statt abgeraeumt.
379
+ """
380
+ _38_json(root, MANIFEST_DD_38,
381
+ lambda d: d["skill_frontmatter"]["tool_names"].pop("read"))
382
+
383
+
384
+ def _38_notiz_weg(root: str) -> None:
385
+ """Eine erklaerte Nichtabbildung ohne Begruendung - eine Behauptung.
386
+
387
+ Ebenfalls hergestellt statt abgeraeumt: Das Verb verliert seine Abbildung und
388
+ bekommt die Erklaerung, aber keine Notiz.
389
+ """
390
+ def _um(d):
391
+ fmt = d["agent_frontmatter"]
392
+ fmt["tool_names"].pop("read")
393
+ fmt["tool_names_unmapped"] = ["read"]
394
+ fmt.pop("_tool_names_unmapped_note", None)
395
+ _38_json(root, MANIFEST_DD_38, _um)
396
+
397
+
398
+ def _38_beides_zugleich(root: str) -> None:
399
+ _38_json(root, MANIFEST_CC_38,
400
+ lambda d: d["skill_frontmatter"].__setitem__("tool_names_unmapped", ["grep"]))
401
+
402
+
403
+ def _38_fremder_schluessel(root: str) -> None:
404
+ """Ein Verb der Durchsetzungsschicht in der Abbildung der Quelle."""
405
+ _38_json(root, MANIFEST_CC_38,
406
+ lambda d: d["agent_frontmatter"]["tool_names"].__setitem__("search", ["Grep"]))
407
+
408
+
409
+ def _38_richtung_verdreht(root: str) -> None:
410
+ """Die Sperrliste wird enger als die Vorabfreigabe - der gefaehrliche Fall."""
411
+ _38_json(root, MANIFEST_CC_38,
412
+ lambda d: d["hook_tools"].__setitem__("write", ["Edit", "NotebookEdit"]))
413
+
414
+
415
+ def _38_quelle_allowed(root: str) -> None:
416
+ ersetze(P(root, SKILL_38.replace("/", os.sep)),
417
+ ("allowed-tools:\r\n - read\r\n", "allowed-tools:\r\n - search\r\n"))
418
+
419
+
420
+ def _38_quelle_deny(root: str) -> None:
421
+ ersetze(P(root, SKILL_38.replace("/", os.sep)),
422
+ (" deny:\r\n - edit\r\n", " deny:\r\n - write\r\n"))
423
+
424
+
425
+ def _38_anker_weg(root: str) -> None:
426
+ """Der Fall, in dem die Pruefung leise bestuende: Das Vokabular verliert seinen Namen."""
427
+ ersetze(P(root, CLIENTMAP_38.replace("/", os.sep)),
428
+ ("FRONTMATTER_VERBEN = (", "FRONTMATTER_VERBEN_ALT = ("))
429
+
430
+
431
+ def _38_quellen_weg(root: str) -> None:
432
+ """Der zweite Anker: ohne Quelldateien prueft der vierte Gegenstand nichts."""
433
+ for rel in (".koolie/core/framework/skills",
434
+ ".koolie/core/framework/role-packs",
435
+ ".koolie/core/framework/runtime/agents"):
436
+ shutil.rmtree(P(root, rel.replace("/", os.sep)), ignore_errors=True)
437
+
438
+
439
+ def _38_engere_vorabfreigabe(root: str) -> None:
440
+ """Die ZULAESSIGE Richtung: die Vorabfreigabe wird enger als die Sperre."""
441
+ _38_json(root, MANIFEST_CC_38,
442
+ lambda d: d["skill_frontmatter"]["tool_names"].__setitem__("edit", ["Edit"]))
443
+
444
+
445
+ sonde("38a", "Ein Verb weder abgebildet noch erklaert - der Stand bis 0.39.0",
446
+ _38_deklaration_weg, "kennt das Werkzeugverb 'read' nicht, und tool_names_unmapped")
447
+
448
+ sonde("38b", "Erklaerte Nichtabbildung ohne Begruendung - eine Behauptung",
449
+ _38_notiz_weg, "'_tool_names_unmapped_note' fehlt")
450
+
451
+ sonde("38c", "Abgebildet und zugleich fuer nicht abgebildet erklaert",
452
+ _38_beides_zugleich, "Beides zugleich geht nicht")
453
+
454
+ sonde("38d", "Ein Verb der Durchsetzungsschicht in der Abbildung der Quelle",
455
+ _38_fremder_schluessel, "kein Verb des Frontmatter-Vokabulars")
456
+
457
+ sonde("38e", "Die Sperrliste wird enger als die Vorabfreigabe - der gefaehrliche Fall",
458
+ _38_richtung_verdreht, "enger als die Vorabfreigabe")
459
+
460
+ sonde("38f", "Eine Quelle nennt in allowed-tools ein fremdes Verb - bis 0.39.0 wurde "
461
+ "es woertlich als Werkzeugname durchgereicht",
462
+ _38_quelle_allowed, "allowed-tools nennt das Verb 'search'")
463
+
464
+ sonde("38g", "Eine Quelle nennt in permissions.deny ein fremdes Verb - bis 0.39.0 "
465
+ "fiel die Sperre lautlos aus",
466
+ _38_quelle_deny, "permissions.deny nennt das Verb 'write'")
467
+
468
+ sonde("38h", "Verlorener Anker - das Vokabular verliert seinen Namen",
469
+ _38_anker_weg, "Pruefung 38 hat ihren Anker verloren")
470
+
471
+ sonde("38i", "Verlorener Anker - keine Quelle mit Frontmatter mehr",
472
+ _38_quellen_weg, "keine Quelle mit Frontmatter gefunden")
473
+
474
+ gegenprobe("38a", "Die unveraenderten Packs bleiben unbeanstandet - eines bildet ab, "
475
+ "eines erklaert", None, "Vokabular")
476
+
477
+ gegenprobe("38b", "Eine Vorabfreigabe, die ENGER ist als die Sperre, bleibt "
478
+ "unbeanstandet - die zulaessige Richtung",
479
+ _38_engere_vorabfreigabe, "enger als die Vorabfreigabe")
480
+
481
+
482
+ # --- 39: Die Vorabfreigabe des Skillaufrufs und die vier Regeltraeger (D-81 bis D-84) -
483
+ #
484
+ # Anlass: Die Wurzel-Anweisungsdatei forderte die Nutzung der Skills, und die
485
+ # ausgelieferte Berechtigungsdatei kannte das Werkzeug dafuer in keinem Korb. Gemessen
486
+ # am 2026-09-14: Der Aufruf wurde abgewiesen, die Sitzung las die SKILL.md ersatzweise
487
+ # als Datei, und die Ausgabe sah aus wie ein gelungener Lauf.
488
+ #
489
+ # Pruefung 39 faengt im Repositorium heute NICHTS - Regeln, Skillmenge und Traegertexte
490
+ # sind mit demselben Release entstanden und passen per Konstruktion zueinander. Was sie
491
+ # wert ist, haengt allein an diesen Sonden. Dieselbe Lage wie bei Pruefung 37, und sie
492
+ # ist im Wirkungsnachweis so ausgewiesen.
493
+ #
494
+ # Die zweite Gegenprobe ist die wichtigere: Gegenstand 3 beanstandet ein Musterzeichen -
495
+ # und die Datei fuehrt daneben Pfadregeln, die eines tragen MUESSEN ('**'). Eine
496
+ # Musterpruefung ohne diese Unterscheidung beanstandete den richtigen Text.
497
+ PERMS_39 = ".koolie/core/framework/runtime/permissions.json"
498
+
499
+
500
+ def _p39(root: str) -> str:
501
+ return P(root, PERMS_39.replace("/", os.sep))
502
+
503
+
504
+ def _39_regel_fehlt(root: str) -> None:
505
+ """Ein ausgelieferter Skill verliert seine Freigabe - der Zustand vor 0.41.0."""
506
+ ersetze(_p39(root),
507
+ (' { "tool": "skill", "pattern": "fw-code-explain" },\r\n', ""))
508
+
509
+
510
+ def _39_regel_ohne_skill(root: str) -> None:
511
+ """Eine Freigabe fuer einen Skill, den es nicht gibt."""
512
+ ersetze(_p39(root),
513
+ ('"pattern": "fw-code-explain" }', '"pattern": "fw-code-erklaeren" }'))
514
+
515
+
516
+ def _39_muster(root: str) -> None:
517
+ """Das Praefixmuster, das gemessen nichts freigibt (D-82)."""
518
+ ersetze(_p39(root),
519
+ ('"pattern": "fw-code-explain" }', '"pattern": "fw-*" }'))
520
+
521
+
522
+ def _39_anker_weg(root: str) -> None:
523
+ """Keine einzige skill-Regel mehr - die Pruefung darf nicht leise bestehen."""
524
+ text = lies(_p39(root))
525
+ zeilen = [z for z in text.split("\r\n") if '"tool": "skill"' not in z]
526
+ if len(zeilen) == len(text.split("\r\n")):
527
+ raise Praeparationsfehler(
528
+ "permissions.json: keine skill-Regel gefunden, die zu entfernen waere")
529
+ # Das Komma der letzten verbleibenden Regel muss weg, sonst ist die Datei kein JSON.
530
+ # Das Komma der letzten verbleibenden Regel vor der schliessenden Klammer muss weg -
531
+ # abgeleitet, nicht an einem Regelnamen: Seit 1.17.0 steht dort nicht mehr git blame.
532
+ schreib(_p39(root), re.sub(r"\},(\s*\r\n\s*\])", r"}\1", "\r\n".join(zeilen)))
533
+
534
+
535
+ def _39_traeger_weg(root: str) -> None:
536
+ """Ein Regeltraeger verliert die Skillwahl - der Zustand vor 0.41.0."""
537
+ ersetze(P(root, ".koolie/core/framework/runtime/rules/00-framework-core.md"
538
+ .replace("/", os.sep)),
539
+ ("**Skillwahl vor dem Schritt.**", "**Hinweis zur Reihenfolge.**"))
540
+
541
+
542
+ def _39_skill_ohne_regel(root: str) -> None:
543
+ """Ein neuer Skill im Verzeichnis, ohne dass jemand die Freigabe nachtraegt."""
544
+ quelle = P(root, ".koolie/core/framework/skills/fw-code-explain"
545
+ .replace("/", os.sep))
546
+ ziel = P(root, ".koolie/core/framework/skills/fw-zwischenstand"
547
+ .replace("/", os.sep))
548
+ shutil.copytree(quelle, ziel)
549
+
550
+
551
+ def _39_pfadmuster_bleibt(root: str) -> None:
552
+ """Gegenprobe: Eine Pfadregel MUSS ein Muster tragen - '**' ist richtig so."""
553
+ ersetze(_p39(root),
554
+ (' { "tool": "read", "pattern": "**" },\r\n',
555
+ ' { "tool": "read", "pattern": "**" },\r\n'
556
+ ' { "tool": "search", "pattern": "src/**" },\r\n'))
557
+
558
+
559
+ sonde("39a", "Ein ausgelieferter Skill ohne Freigabe - der Zustand vor 0.41.0",
560
+ _39_regel_fehlt, "hat keine allow-Regel")
561
+
562
+ sonde("39b", "Eine Freigabe fuer einen Skill, den es nicht gibt",
563
+ _39_regel_ohne_skill, "nennt keinen ausgelieferten Skill")
564
+
565
+ sonde("39c", "Ein Praefixmuster in der Freigabe - es gaebe lautlos nichts frei (D-82)",
566
+ _39_muster, "traegt ein Musterzeichen")
567
+
568
+ sonde("39d", "Verlorener Anker - keine einzige skill-Regel mehr",
569
+ _39_anker_weg, "keine einzige allow-Regel mit dem Verb 'skill'")
570
+
571
+ sonde("39e", "Ein Regeltraeger verliert die Skillwahl",
572
+ _39_traeger_weg, "die Skillwahl fehlt")
573
+
574
+ sonde("39f", "Ein neuer Skill, dessen Freigabe niemand nachtraegt",
575
+ _39_skill_ohne_regel, "'fw-zwischenstand' hat keine allow-Regel")
576
+
577
+ gegenprobe("39a", "Die unveraenderte Datei bleibt unbeanstandet - zwoelf Regeln, zwoelf "
578
+ "Skills", None, "allow-Regel")
579
+
580
+ gegenprobe("39b", "Eine PFADregel mit Muster bleibt unbeanstandet - Gegenstand 3 misst "
581
+ "nur die skill-Regeln", _39_pfadmuster_bleibt, "Musterzeichen")
582
+
583
+
584
+
585
+ # --- 40: Die Register des Pruefapparats (D-85, D-86) ---------------------------------
586
+ #
587
+ # Anlass: Fuenf Aussagen ueber den eigenen Pruefstand, keine davon richtig - und keine
588
+ # falsch geschrieben. Alle fuenf waren bei ihrer Einfuehrung richtig und sind stehen
589
+ # geblieben, waehrend ihr Gegenstand wuchs; die aelteste seit zwoelf Releases.
590
+ #
591
+ # Diese Sonden sind der Grund, warum die Pruefung mehr ist als eine Textaenderung: Sie
592
+ # belegen, dass das Vergessen gefangen wird, nicht nur das einmalige Nachziehen.
593
+ #
594
+ # Die zweite Gegenprobe ist die wichtigere. Der erste Entwurf dieser Pruefung hat einen
595
+ # Querverweis im Fliesstext eines Kommentars fuer einen Kopf gehalten und Pruefung 37
596
+ # dort gefunden, wo kein Kopf steht. Seither ankert sie an der hoechsten genannten
597
+ # Nummer statt an einer Kommentarform - und diese Gegenprobe haelt genau das fest.
598
+ VAL_40 = ".koolie/core/tests/scripts/validate-framework.py"
599
+ KAT_40 = ".koolie/core/tests/TEST_CATALOG.md"
600
+
601
+ REGISTER_KOPF = "Prüft (statisch, ohne laufenden KI-Client):"
602
+ NACHWEIS_ANFANG = "Der Wirksamkeitsnachweis nach D-23 fuer die Pruefungen "
603
+
604
+
605
+ def _zeilenblock(*zeilen: str) -> str:
606
+ """Ein Block des Registers als CRLF-Text - der Kopfkommentar ist CRLF wie die Datei."""
607
+ return "".join(z + "\r\n" for z in zeilen)
608
+
609
+
610
+ EINTRAG_25 = _zeilenblock(
611
+ " 25. Ausfall mit Ersatz (D-41): Eine Matrixzeile eines Client Packs auf "
612
+ "[NICHT ABBILDBAR]",
613
+ " benennt den Ersatz - oder haelt ausdruecklich fest, dass es keinen gibt")
614
+
615
+
616
+ def _p40v(root: str) -> str:
617
+ return P(root, VAL_40.replace("/", os.sep))
618
+
619
+
620
+ def _p40k(root: str) -> str:
621
+ return P(root, KAT_40.replace("/", os.sep))
622
+
623
+
624
+ def _40_registerblock(text: str):
625
+ """Der LETZTE nummerierte Registereintrag: (anfang, zeilen, i, j, nummer).
626
+
627
+ Abgeleitet statt verdrahtet. Die erste Fassung dieser Sonden trug die Nummer des
628
+ eigenen Releases im Suchtext und fiel mit der naechsten Pruefung: 40a meldete eine
629
+ Luecke statt des fehlenden letzten Eintrags, 40c ergaenzte eine Nummer, die es
630
+ inzwischen wirklich gibt. Eine Sonde, die ihre Grenze selbst ausrechnet, ueberlebt
631
+ das Release, das sie pruefen soll.
632
+ """
633
+ a = text.index(REGISTER_KOPF)
634
+ b = text.index(NACHWEIS_ANFANG, a)
635
+ zeilen = text[a:b].split("\r\n")
636
+ starts = [i for i, z in enumerate(zeilen) if re.match(r"^ ?\d+\. ", z)]
637
+ if not starts:
638
+ raise Praeparationsfehler(
639
+ "validate-framework.py: kein nummerierter Registereintrag gefunden")
640
+ i = starts[-1]
641
+ j = i + 1
642
+ while j < len(zeilen) and zeilen[j].startswith(" "):
643
+ j += 1
644
+ return a, b, zeilen, i, j, int(zeilen[i].split(".", 1)[0].strip())
645
+
646
+
647
+ def _40_eintrag_fehlt(root: str) -> None:
648
+ """Der Zustand vom 2026-09-14: Eine Pruefung laeuft, das Register kennt sie nicht."""
649
+ pfad = _p40v(root)
650
+ text = lies(pfad)
651
+ a, b, zeilen, i, j, _nr = _40_registerblock(text)
652
+ schreib(pfad, text[:a] + "\r\n".join(zeilen[:i] + zeilen[j:]) + text[b:])
653
+
654
+
655
+ def _40_luecke(root: str) -> None:
656
+ """Eine Nummer faellt aus dem Register - die Pruefung dahinter findet niemand."""
657
+ ersetze(_p40v(root), (EINTRAG_25, ""))
658
+
659
+
660
+ def _40_eintrag_ohne_pruefung(root: str) -> None:
661
+ """Ein Eintrag ohne Pruefung dahinter - die Gegenrichtung von 40a."""
662
+ pfad = _p40v(root)
663
+ text = lies(pfad)
664
+ a, b, zeilen, _i, j, nummer = _40_registerblock(text)
665
+ zusatz = [" %d. Eine Zeile, der keine Pruefung entspricht - sie verspricht mehr,"
666
+ % (nummer + 1),
667
+ " als der Lauf leistet"]
668
+ schreib(pfad, text[:a] + "\r\n".join(zeilen[:j] + zusatz + zeilen[j:]) + text[b:])
669
+
670
+
671
+ def _40_spanne_verdreht(root: str) -> None:
672
+ """Die Sondenmenge im Satz unter dem Register weicht ab - der Stand von 0.32.0.
673
+
674
+ Die Spanne wird gesucht, nicht genannt: Sie waechst mit jedem Release.
675
+ """
676
+ pfad = _p40v(root)
677
+ text = lies(pfad)
678
+ neu, treffer = re.subn(r"(" + re.escape(NACHWEIS_ANFANG) + r")[^\r\n]*?( laeuft)",
679
+ r"\g<1>18 bis 30\g<2>", text, count=1)
680
+ if treffer != 1:
681
+ raise Praeparationsfehler(
682
+ "validate-framework.py: Satz zum Wirkungsnachweis nicht gefunden")
683
+ schreib(pfad, neu)
684
+
685
+
686
+ def _40_grenzfallzahl(root: str) -> None:
687
+ """FW-KO-05 nennt eine Zahl, die nicht mehr stimmt - der Stand bis 0.41.0."""
688
+ ersetze(_p40k(root),
689
+ ("Die 20 Grenzfälle einzeln", "Die zwölf Grenzfälle einzeln"))
690
+
691
+
692
+ def _40_anker_weg(root: str) -> None:
693
+ """Die Registerueberschrift verschwindet - die Pruefung darf nicht leise bestehen."""
694
+ ersetze(_p40v(root),
695
+ ("Prüft (statisch, ohne laufenden KI-Client):\r\n 1. Pflichtdateien",
696
+ "Geprüft wird unter anderem:\r\n 1. Pflichtdateien"))
697
+
698
+
699
+ def _40_querverweis(root: str) -> None:
700
+ """Gegenprobe: Ein Querverweis auf eine kleinere Nummer ist kein Registereintrag.
701
+
702
+ Genau diese Zeilenform hat den ersten Entwurf der Pruefung fallen lassen.
703
+ """
704
+ ersetze(_p40v(root),
705
+ ("def main() -> int:\r\n",
706
+ "# Pruefung 37 und dieselbe Ehrlichkeit wie Pruefung 30: ein Querverweis im\r\n"
707
+ "# Fliesstext, kein Kopf - er darf das Register nicht bewegen.\r\n"
708
+ "def main() -> int:\r\n"))
709
+
710
+
711
+ sonde("40a", "Eine Pruefung laeuft, das Register kennt sie nicht - der Fall vom "
712
+ "2026-09-14", _40_eintrag_fehlt, "die Prüfskripte nennen Prüfung")
713
+
714
+ sonde("40b", "Eine Nummer faellt aus dem Register - die Pruefung dahinter findet "
715
+ "niemand", _40_luecke, "hat Lücken – es fehlt 25")
716
+
717
+ sonde("40c", "Ein Registereintrag ohne Pruefung dahinter - die Gegenrichtung",
718
+ _40_eintrag_ohne_pruefung, "Ein Eintrag ohne Prüfung verspricht mehr")
719
+
720
+ sonde("40d", "Die Sondenmenge im Satz unter dem Register weicht ab",
721
+ _40_spanne_verdreht,
722
+ "validate-framework.py: die Sondenmenge ist dort nicht in der ausgerechneten")
723
+
724
+ sonde("40e", "FW-KO-05 nennt eine Grenzfallzahl, die nicht mehr stimmt",
725
+ _40_grenzfallzahl, "FW-KO-05 nennt nicht die gezählte Anzahl")
726
+
727
+ sonde("40f", "Verlorener Anker - die Registerueberschrift verschwindet",
728
+ _40_anker_weg, "Prüfung 40 hat ihren Gegenstand verloren")
729
+
730
+ gegenprobe("40a", "Das unveraenderte Repositorium bleibt unbeanstandet - Register, "
731
+ "Sondenmenge und Grenzfallzahl decken sich", None,
732
+ "das Register im Kopfkommentar")
733
+
734
+ gegenprobe("40b", "Ein Querverweis auf eine kleinere Pruefungsnummer bleibt "
735
+ "unbeanstandet - er ist kein Kopf und kein Eintrag",
736
+ _40_querverweis, "die Prüfskripte nennen Prüfung")
737
+
738
+
739
+ # --- 41: Abwesenheitsbeleg, und 38 mit eigenem Namensraum (D-88) ----------------------
740
+ #
741
+ # Anlass: Eine Abwesenheitserklaerung nahm eine Werkzeugklasse aus der Durchsetzung und
742
+ # begruendete es - mit einem Satz, der weder Enthaltung noch Beleg war. Pruefung 26 hat
743
+ # ihn durchgelassen, weil sie Folgerichtigkeit prueft und nicht Wahrheit.
744
+ #
745
+ # Die zweite Gegenprobe ist die wichtigere: Eine Enthaltung braucht KEINEN Beleg. Wer das
746
+ # verwechselt, verlangt fuer eine ehrliche Wissenslucke ein Protokoll, das es nicht geben
747
+ # kann - und treibt damit genau die Behauptung hervor, gegen die die Pruefung gebaut ist.
748
+ MAN_DD = ".koolie/core/clients/devin-desktop/manifest.json"
749
+ MAN_CC = ".koolie/core/clients/claude-code/manifest.json"
750
+
751
+ # Der Anker zeigt auf den SCHLUESSEL, nicht auf seinen Wert: Der Wert hat sich mit
752
+ # 0.86.0 geaendert (von "UNERHOBEN, nicht abwesend" auf "ERHOBEN am 2026-09-22"), und
753
+ # eine Sonde, die am Wert haengt, verliert ihren Gegenstand beim naechsten Messwert.
754
+ NOTE_DD_START = '"_agent_start_tools_absent_note": '
755
+ NOTE_CC_FUND = ("tests/protocols/2026-09-13-erhebung-disallowed-tools.md "
756
+ "Abschnitt 4.3")
757
+
758
+
759
+ def _41_behauptung(root: str) -> None:
760
+ """Eine Abwesenheitserklaerung ohne Enthaltung und ohne Fundstelle - der Fall vom
761
+ 2026-09-14. Die Note traegt danach noch ein Datum, aber keinen Beleg."""
762
+ t = lies(_p(root, MAN_DD))
763
+ t = t.replace('"agent_start_tools_absent": [],',
764
+ '"agent_start_tools_absent": ["unerhoben"],', 1)
765
+ anfang = t.index(NOTE_DD_START)
766
+ ende = t.index('",', anfang)
767
+ t = (t[:anfang] + '"_agent_start_tools_absent_note": "Dieser Client fuehrt kein '
768
+ 'Startwerkzeug fuer Unteragenten.' + t[ende:])
769
+ schreib(_p(root, MAN_DD), t)
770
+
771
+
772
+ def _41_datum_ohne_fundstelle(root: str) -> None:
773
+ """Ein Datum allein ist kein Beleg - die Fundstelle faellt weg."""
774
+ ersetze(_p(root, MAN_CC), (NOTE_CC_FUND, "einer fruehreren Erhebung"))
775
+
776
+
777
+ def _41_gegenstand_weg(root: str) -> None:
778
+ """Kein Pack fuehrt noch eine Abwesenheitserklaerung - die Pruefung meldet es selbst.
779
+
780
+ DIE SONDE MUSS JEDES PACK TREFFEN, UND MIT DEM DRITTEN IST SIE DARAN GESCHEITERT
781
+ (CR-2026-133). Sie nannte bis 1.3.0 zwei Packs beim Namen; `openai-codex` fuehrt
782
+ gleich vier Abwesenheitserklaerungen, und der Anker war deshalb nicht verloren -
783
+ die Sonde meldete FEHL, obwohl die Pruefung richtig gearbeitet hat.
784
+ ➡️ Eine Sonde, die ihre Gegenstaende aufzaehlt, altert mit jedem neuen.
785
+ Sie raeumt deshalb jetzt JEDES Manifest der Ablage, und zwar ueber die GESTALT der
786
+ Schluessel (`*_absent`, `*_unmapped`) statt ueber ihre Namen.
787
+ """
788
+ def raeumen(obj):
789
+ if isinstance(obj, dict):
790
+ for k in [k for k in obj if k.endswith(("_absent", "_unmapped"))]:
791
+ del obj[k]
792
+ for v in obj.values():
793
+ raeumen(v)
794
+ elif isinstance(obj, list):
795
+ for v in obj:
796
+ raeumen(v)
797
+
798
+ basis = _p(root, ".koolie/core/clients")
799
+ treffer = 0
800
+ for name in sorted(os.listdir(basis)):
801
+ pfad = os.path.join(basis, name, "manifest.json")
802
+ if not os.path.isfile(pfad):
803
+ continue
804
+ daten = json.loads(lies(pfad))
805
+ raeumen(daten)
806
+ schreib(pfad, json.dumps(daten, indent=2, ensure_ascii=False) + chr(10))
807
+ treffer += 1
808
+ if treffer < 2:
809
+ raise Praeparationsfehler(
810
+ "Sonde 41c: weniger als zwei Manifeste gefunden - die Sonde hat ihren "
811
+ "Gegenstand verloren")
812
+
813
+
814
+ def _41_enthaltung_ohne_beleg(root: str) -> None:
815
+ """Gegenprobe: Eine Enthaltung braucht keinen Beleg - sie ist selbst die Aussage."""
816
+ text = lies(_p(root, MAN_CC))
817
+ anfang = text.index('"_skill_deny_unmapped_note": "')
818
+ ende = text.index('",', anfang)
819
+ neu = ('"_skill_deny_unmapped_note": "Unerhoben: Ob dieser Client befehlsgenaue '
820
+ 'Verbote auswertet, ist nicht gemessen.')
821
+ schreib(_p(root, MAN_CC), text[:anfang] + neu + text[ende:])
822
+
823
+
824
+ def _38_namensraum_ohne_notiz(root: str) -> None:
825
+ """Ein eigener Namensraum nimmt die Richtungsregel ausser Kraft - ohne Begruendung."""
826
+ text = lies(_p(root, MAN_DD))
827
+ anfang = text.index('"_tool_names_note": "ERHOBEN am 2026-09-14')
828
+ ende = text.index('",', anfang)
829
+ schreib(_p(root, MAN_DD), text[:anfang] + '"_tool_names_note": "' + text[ende:])
830
+
831
+
832
+ def _38_namensraum_falsch(root: str) -> None:
833
+ """Der Namensraum wird auf 'werkzeugnamen' gestellt - die Richtungsregel muss greifen."""
834
+ ersetze(_p(root, MAN_DD),
835
+ ('"tool_names_namespace": "eigen",', '"tool_names_namespace": "werkzeugnamen",', 2))
836
+
837
+
838
+ sonde("41a", "Abwesenheitserklaerung ohne Enthaltung und ohne Fundstelle - der Fall "
839
+ "vom 2026-09-14", _41_behauptung,
840
+ "weder als Enthaltung aus noch belegt sie sie")
841
+
842
+ sonde("41b", "Ein Datum allein ist kein Beleg", _41_datum_ohne_fundstelle,
843
+ "weder als Enthaltung aus noch belegt sie sie")
844
+
845
+ sonde("41c", "Verlorener Gegenstand - kein Pack erklaert mehr eine Abwesenheit",
846
+ _41_gegenstand_weg, "hat ihren Gegenstand verloren")
847
+
848
+ sonde("38j", "Eigener Namensraum ohne Begruendung - die Richtungsregel faellt "
849
+ "unbegruendet weg", _38_namensraum_ohne_notiz,
850
+ "tool_names_namespace ist 'eigen', aber")
851
+
852
+ sonde("38k", "Namensraum auf 'werkzeugnamen' gestellt - die Richtungsregel muss greifen",
853
+ _38_namensraum_falsch, "Die Sperrliste ist damit enger als die Vorabfreigabe")
854
+
855
+ gegenprobe("41a", "Die unveraenderten Packs bleiben unbeanstandet - eine Enthaltung und "
856
+ "ein Beleg", None, "weder als Enthaltung aus noch belegt sie sie")
857
+
858
+ gegenprobe("41b", "Eine Enthaltung ohne Datum und ohne Fundstelle bleibt unbeanstandet - "
859
+ "sie ist selbst die Aussage", _41_enthaltung_ohne_beleg,
860
+ "weder als Enthaltung aus noch belegt sie sie")
861
+
862
+ # --- 42: Ein gefuellter Schlitz traegt, was das Overlay erklaert ----------------------
863
+ #
864
+ # Gegen eine frische INSTALLATION beider Packs, nicht gegen eine Kopie des
865
+ # Repositoriums - der Gegenstand sind zwei installierte Dateien (das Overlay und die
866
+ # Berechtigungsdatei), nicht ein Repositoriumstext. Dieselbe Bauart wie bei den
867
+ # Pruefungen 33 und 37, und aus demselben Grund: Befund B02 trifft jede Pruefung, die
868
+ # an einer Installation haengt.
869
+ #
870
+ # Die Gegenproben sind hier die wichtigere Haelfte, in drei Zuschnitten: der
871
+ # Auslieferungszustand (Overlay dreimal <TBD>, Schlitze woertlich offen), das ordentlich
872
+ # ausgefuellte Projekt (drei erklaerte Befehle, drei passende Regeln) und das Projekt
873
+ # OHNE Lintbefehl, das seinen Schlitz streicht. Eine Pruefung, die einen dieser drei
874
+ # beanstandet, beanstandet jedes echte Projekt.
875
+ #
876
+ # Die Meldungstexte sind umlautfrei gewaehlt, damit sie hier so stehen koennen, wie sie
877
+ # im Validator stehen.
878
+ M42_UNERKLAERT = "und kein Platzhalter des Overlays"
879
+ M42_OFFEN = "aber noch den offenen Schlitz"
880
+ M42_ABWEICHUNG = "ist eine Abweichung"
881
+ M42_ANKER = "keine Tabellenzeile nennt"
882
+ M42_MEHRDEUTIG = "Tabellenzeilen nennen"
883
+ M42_ALLE = (M42_UNERKLAERT, M42_OFFEN, M42_ABWEICHUNG, M42_ANKER, M42_MEHRDEUTIG)
884
+
885
+
886
+ def _42_overlay_pfad(root: str) -> str:
887
+ return os.path.join(root, ".koolie/project-overlay", "OVERLAY.md")
888
+
889
+
890
+ def _42_zeile(root: str, platzhalter: str) -> tuple:
891
+ """Index und Zeilen des Overlays - der Platzhalter muss in genau einer Zeile stehen."""
892
+ zeilen = lies(_42_overlay_pfad(root)).splitlines(True)
893
+ treffer = [i for i, z in enumerate(zeilen)
894
+ if z.lstrip().startswith("|") and ("`%s`" % platzhalter) in z]
895
+ if len(treffer) != 1:
896
+ raise Praeparationsfehler(
897
+ "OVERLAY.md: %s steht in %d Tabellenzeilen, erwartet genau eine - die "
898
+ "Sonde hat ihren Gegenstand verloren" % (platzhalter, len(treffer)))
899
+ return treffer[0], zeilen
900
+
901
+
902
+ def _42_erklaert(root: str, platzhalter: str, wert: str) -> None:
903
+ """Den Befehl neben einem Platzhalter setzen - der Wert muss sich aendern."""
904
+ i, zeilen = _42_zeile(root, platzhalter)
905
+ roh = zeilen[i]
906
+ ende = roh[len(roh.rstrip("\r\n")):]
907
+ felder = roh.rstrip("\r\n").split("|")
908
+ for k, feld in enumerate(felder):
909
+ if feld.strip("` *") == platzhalter and k + 1 < len(felder):
910
+ if felder[k + 1].strip("` *") == wert:
911
+ raise Praeparationsfehler(
912
+ "OVERLAY.md: %s erklaert bereits %r - die Sonde praepariert nichts"
913
+ % (platzhalter, wert))
914
+ felder[k + 1] = " `%s` " % wert
915
+ break
916
+ else:
917
+ raise Praeparationsfehler(
918
+ "OVERLAY.md: keine Zelle rechts neben %s - die Tabellenform hat sich "
919
+ "geaendert" % platzhalter)
920
+ zeilen[i] = "|".join(felder) + ende
921
+ schreib(_42_overlay_pfad(root), "".join(zeilen))
922
+
923
+
924
+ def _42_platzhalter_weg(root: str, platzhalter: str) -> None:
925
+ """Den Platzhalter aus seiner Zelle nehmen - der verlorene Anker."""
926
+ i, zeilen = _42_zeile(root, platzhalter)
927
+ zeilen[i] = zeilen[i].replace("`%s`" % platzhalter, "keiner")
928
+ schreib(_42_overlay_pfad(root), "".join(zeilen))
929
+
930
+
931
+ def _42_zeile_doppeln(root: str, platzhalter: str) -> None:
932
+ """Die Zeile ein zweites Mal anlegen - zwei Zeilen, zwei moegliche Befehle."""
933
+ i, zeilen = _42_zeile(root, platzhalter)
934
+ zeilen.insert(i + 1, zeilen[i])
935
+ schreib(_42_overlay_pfad(root), "".join(zeilen))
936
+
937
+
938
+ def _42_rechte(root: str, rel: str, *aenderungen) -> None:
939
+ """Die Berechtigungsdatei eines beliebigen Packs praeparieren.
940
+
941
+ Die Waechter sitzen in den Eingriffen selbst (_37_weg, _37_dazu, _37_statt), die
942
+ hier wiederverwendet werden - ein Textvergleich taugte fuer eine JSON-Datei nicht
943
+ (D-74).
944
+ """
945
+ pfad = os.path.join(root, *rel.split("/"))
946
+ daten = json.loads(lies(pfad))
947
+ for aenderung in aenderungen:
948
+ aenderung(daten)
949
+ schreib(pfad, json.dumps(daten, indent=2, ensure_ascii=False) + "\n")
950
+
951
+
952
+ def _42_trifft(root: str, erwartet) -> bool:
953
+ """Ein Validatorlauf gegen die erwartete Meldung.
954
+
955
+ erwartet als Zeichenkette: Die Meldung MUSS vorkommen (Sonde).
956
+ erwartet als Tupel: KEINE der Meldungen darf vorkommen (Gegenprobe).
957
+
958
+ Ohne Ergebniszeile ist der Lauf kein Messwert, sondern ein Abbruch - dann gilt er
959
+ als nicht bestanden (Arbeitswissen vom 2026-09-14).
960
+ """
961
+ aus = validator_ausgabe(root)
962
+ if "Ergebnis:" not in aus:
963
+ notiz(" Kein Messwert: der Lauf hat keine Ergebniszeile geliefert.")
964
+ return False
965
+ if isinstance(erwartet, str):
966
+ if erwartet not in aus:
967
+ notiz(" Ausgabe:", " | ".join(
968
+ z for z in aus.splitlines() if "FEHLER" in z)[:400])
969
+ return False
970
+ return True
971
+ uebrig = [m for m in erwartet if m in aus]
972
+ if uebrig:
973
+ notiz(" Unerwartet gemeldet:", ", ".join(uebrig))
974
+ notiz(" Ausgabe:", " | ".join(
975
+ z for z in aus.splitlines() if "FEHLER" in z)[:400])
976
+ return False
977
+ return True
978
+
979
+
980
+ def sonden_schlitzinhalte() -> None:
981
+ """Wirkungsnachweis zu Pruefung 42 (CR-2026-066, D-90 und D-91)."""
982
+ # Seit 1.18.2 fuehrt claude-code ZWEI Befehlswerkzeuge (D-469): Jeder Befehlsschlitz steht
983
+ # als Bash(...) und PowerShell(...) in der Datei, und ein ordentlich gefuelltes Projekt fuellt
984
+ # beide. Die Sonden fuellen nur den ersten - ihr Befund liegt dort.
985
+ for pack, rechte, werkzeuge in (("claude-code", ".claude/settings.json", ("Bash", "PowerShell")),
986
+ ("devin-desktop", ".devin/config.json", ("Exec",))):
987
+ werkzeug = werkzeuge[0]
988
+ root = installation(pack)
989
+ try:
990
+ pfad_r = os.path.join(root, *rechte.split("/"))
991
+ pfad_o = _42_overlay_pfad(root)
992
+ ausgang_r, ausgang_o = lies(pfad_r), lies(pfad_o)
993
+ schreib(os.path.join(root, "README.md"), "# Sondenprojekt\r\n")
994
+
995
+ def zurueck():
996
+ schreib(pfad_r, ausgang_r)
997
+ schreib(pfad_o, ausgang_o)
998
+
999
+ def sch(name):
1000
+ return "%s(<%s>)" % (werkzeug, name)
1001
+
1002
+ def rg(befehl):
1003
+ return "%s(%s)" % (werkzeug, befehl)
1004
+
1005
+ # --- Gegenprobe 42a: der Auslieferungszustand -----------------------
1006
+ melde("GEGENPROBE", "42a", _42_trifft(root, M42_ALLE),
1007
+ "Auslieferungszustand: Overlay dreimal <TBD>, drei offene Schlitze "
1008
+ "(%s)" % pack)
1009
+
1010
+ # --- Gegenprobe 42b: das ordentlich ausgefuellte Projekt ------------
1011
+ for name, befehl in (("BUILD_COMMAND", "mvn -B clean package"),
1012
+ ("TEST_COMMAND", "mvn -B test"),
1013
+ ("LINT_COMMAND", "mvn -B verify")):
1014
+ _42_erklaert(root, "<%s>" % name, befehl)
1015
+ for w in werkzeuge:
1016
+ _42_rechte(root, rechte, lambda d, n=name, b=befehl, w=w: _37_statt(
1017
+ d, "ask", "%s(<%s>)" % (w, n), "%s(%s)" % (w, b)))
1018
+ melde("GEGENPROBE", "42b", _42_trifft(root, M42_ALLE),
1019
+ "Drei erklaerte Befehle, drei passende Regeln - der Normalfall "
1020
+ "(%s)" % pack)
1021
+ zurueck()
1022
+
1023
+ # --- Gegenprobe 42c: kein Lintbefehl, Schlitz gestrichen ------------
1024
+ # Der zulaessige Weg fuer ein Projekt ohne Formatpruefung. Er darf nicht
1025
+ # teurer sein als der unzulaessige.
1026
+ _42_erklaert(root, "<BUILD_COMMAND>", "mvn -B clean package")
1027
+ _42_erklaert(root, "<TEST_COMMAND>", "mvn -B test")
1028
+ _42_erklaert(root, "<LINT_COMMAND>", "nicht vorhanden")
1029
+ for w in werkzeuge:
1030
+ _42_rechte(root, rechte,
1031
+ lambda d, w=w: _37_statt(d, "ask", "%s(<BUILD_COMMAND>)" % w,
1032
+ "%s(mvn -B clean package)" % w),
1033
+ lambda d, w=w: _37_statt(d, "ask", "%s(<TEST_COMMAND>)" % w,
1034
+ "%s(mvn -B test)" % w),
1035
+ lambda d, w=w: _37_weg(d, "ask", "%s(<LINT_COMMAND>)" % w))
1036
+ melde("GEGENPROBE", "42c", _42_trifft(root, M42_ALLE),
1037
+ "Kein Lintbefehl, Schlitz gestrichen - der zulaessige Weg "
1038
+ "(%s)" % pack)
1039
+ zurueck()
1040
+
1041
+ # --- Sonde 42a: der Fall des Piloten --------------------------------
1042
+ # Das Overlay sagt "nicht vorhanden", die Datei gewaehrt einen dritten
1043
+ # Befehl. Pruefung 37 schweigt dazu, weil drei Schlitze drei Zeilen decken.
1044
+ _42_erklaert(root, "<BUILD_COMMAND>", "mvn -B clean package")
1045
+ _42_erklaert(root, "<TEST_COMMAND>", "mvn -B test")
1046
+ _42_erklaert(root, "<LINT_COMMAND>", "nicht vorhanden")
1047
+ _42_rechte(root, rechte,
1048
+ lambda d: _37_statt(d, "ask", sch("BUILD_COMMAND"),
1049
+ rg("mvn -B clean package")),
1050
+ lambda d: _37_statt(d, "ask", sch("TEST_COMMAND"),
1051
+ rg("mvn -B test")),
1052
+ lambda d: _37_statt(d, "ask", sch("LINT_COMMAND"),
1053
+ rg("mvn -B -q compile")))
1054
+ melde("SONDE", "42a", _42_trifft(root, M42_UNERKLAERT),
1055
+ "Der Fall des Piloten: Overlay sagt 'nicht vorhanden', die Datei "
1056
+ "gewaehrt einen dritten Befehl (%s)" % pack)
1057
+ zurueck()
1058
+
1059
+ # --- Sonde 42b: das Overlay erklaert gar nichts ---------------------
1060
+ # Der Lauf M10 der Gegenpruefung: drei <TBD> decken drei Freigaben,
1061
+ # darunter eine mit Fernwirkung.
1062
+ _42_rechte(root, rechte,
1063
+ lambda d: _37_statt(d, "ask", sch("BUILD_COMMAND"),
1064
+ rg("mvn -B clean package")),
1065
+ lambda d: _37_statt(d, "ask", sch("TEST_COMMAND"),
1066
+ rg("mvn -B test")),
1067
+ lambda d: _37_statt(d, "ask", sch("LINT_COMMAND"),
1068
+ rg("mvn -B deploy")))
1069
+ melde("SONDE", "42b", _42_trifft(root, M42_UNERKLAERT),
1070
+ "Overlay erklaert dreimal <TBD>, die Datei gewaehrt drei Befehle - "
1071
+ "einer davon mit Fernwirkung (%s)" % pack)
1072
+ zurueck()
1073
+
1074
+ # --- Sonde 42c: der Schlitz traegt einen anderen Befehl -------------
1075
+ _42_erklaert(root, "<TEST_COMMAND>", "mvn -B test")
1076
+ _42_rechte(root, rechte, lambda d: _37_statt(
1077
+ d, "ask", sch("TEST_COMMAND"), rg("mvn -B verify")))
1078
+ melde("SONDE", "42c", _42_trifft(root, M42_ABWEICHUNG),
1079
+ "Gefuellter Schlitz mit fremdem Befehl - der Fall, den Kandidat 2 "
1080
+ "beschrieb (%s)" % pack)
1081
+ zurueck()
1082
+
1083
+ # --- Sonde 42d: erklaert, aber der Schlitz steht noch offen ---------
1084
+ _42_erklaert(root, "<TEST_COMMAND>", "mvn -B test")
1085
+ melde("SONDE", "42d", _42_trifft(root, M42_OFFEN),
1086
+ "Das Overlay erklaert einen Befehl, die Datei traegt noch den "
1087
+ "offenen Schlitz (%s)" % pack)
1088
+ zurueck()
1089
+
1090
+ # --- Sonde 42e: der verlorene Anker ---------------------------------
1091
+ _42_platzhalter_weg(root, "<LINT_COMMAND>")
1092
+ melde("SONDE", "42e", _42_trifft(root, M42_ANKER),
1093
+ "Verlorener Anker - keine Tabellenzeile nennt den Platzhalter mehr "
1094
+ "(%s)" % pack)
1095
+ zurueck()
1096
+
1097
+ # --- Sonde 42f: zwei Zeilen fuer denselben Platzhalter --------------
1098
+ _42_zeile_doppeln(root, "<TEST_COMMAND>")
1099
+ melde("SONDE", "42f", _42_trifft(root, M42_MEHRDEUTIG),
1100
+ "Zwei Tabellenzeilen nennen denselben Platzhalter - welcher Befehl "
1101
+ "gilt? (%s)" % pack)
1102
+ zurueck()
1103
+ finally:
1104
+ aufraeumen(os.path.dirname(root))
1105
+
1106
+
1107
+ buendel(sonden_schlitzinhalte,
1108
+ "Der Inhalt der drei Befehlsschlitze gegen die Berechtigungsdatei, je Pack: "
1109
+ "unerklaerter Befehl, fremder Befehl, offener Schlitz, verlorener Anker, doppelte Zeile")
1110
+
1111
+ M43_FEHLT = "trägt keinen 'hooks'-Block"
1112
+ M43_LEER = "ohne ein einziges PreToolUse-Kommando"
1113
+ M43_ALLE = (M43_FEHLT, M43_LEER)
1114
+
1115
+ # Dieselbe Lagepruefung wie bei Pruefung 42: Ein String MUSS in der Ausgabe stehen, eine
1116
+ # Liste von Strings darf NICHT darin stehen. Sie ist nicht an 42 gebunden.
1117
+ _43_trifft = _42_trifft
1118
+
1119
+
1120
+ def _43_block_weg(pfad: str) -> None:
1121
+ """Den hooks-Block entfernen - der Fall des Uebungsrepositoriums.
1122
+
1123
+ Der Waechter sitzt im Eingriff, nicht in einem Textvergleich: json.dumps
1124
+ normalisiert die Datei ohnehin (dieselbe Zusage wie D-74, siehe _37_schreiben).
1125
+ """
1126
+ daten = json.loads(lies(pfad))
1127
+ if "hooks" not in daten:
1128
+ raise Praeparationsfehler(
1129
+ "%s: es gibt keinen hooks-Block zu entfernen; die Sonde hat ihren "
1130
+ "Gegenstand verloren" % os.path.basename(pfad))
1131
+ del daten["hooks"]
1132
+ schreib(pfad, json.dumps(daten, indent=2, ensure_ascii=False) + "\n")
1133
+
1134
+
1135
+ def _43_block_leeren(pfad: str) -> None:
1136
+ """Den hooks-Block behalten, PreToolUse leeren - die halbe Migration."""
1137
+ daten = json.loads(lies(pfad))
1138
+ hooks = daten.get("hooks")
1139
+ if not isinstance(hooks, dict) or not hooks.get("PreToolUse"):
1140
+ raise Praeparationsfehler(
1141
+ "%s: kein PreToolUse-Eintrag zum Leeren vorhanden" % os.path.basename(pfad))
1142
+ hooks["PreToolUse"] = []
1143
+ schreib(pfad, json.dumps(daten, indent=2, ensure_ascii=False) + "\n")
1144
+
1145
+
1146
+ def sonden_hookblock() -> None:
1147
+ """Wirkungsnachweis zu Pruefung 43 (CR-2026-067, D-92)."""
1148
+ # Der verwaiste Dateiname ist fuer beide Packs derselbe: VERWAISTE_HOOK_DATEIEN
1149
+ # im Validator fuehrt genau einen. Die erste Fassung dieser Sonde riet fuer
1150
+ # claude-code "hooks.json" und fiel - an der Sonde, nicht an der Pruefung.
1151
+ for pack, rechte in (("claude-code", ".claude/settings.json"),
1152
+ ("devin-desktop", ".devin/config.json")):
1153
+ verwaist = "hooks.v1.json"
1154
+ root = installation(pack)
1155
+ try:
1156
+ pfad = os.path.join(root, *rechte.split("/"))
1157
+ ausgang = lies(pfad)
1158
+ schreib(os.path.join(root, "README.md"), "# Sondenprojekt\r\n")
1159
+
1160
+ # --- Gegenprobe 43a: der Auslieferungszustand ------------------------
1161
+ melde("GEGENPROBE", "43a", _43_trifft(root, M43_ALLE),
1162
+ "Auslieferungszustand: der Block steht in der Berechtigungsdatei "
1163
+ "(%s)" % pack)
1164
+
1165
+ # --- Sonde 43a: der Fall des Uebungsrepositoriums --------------------
1166
+ # Einunddreissig Releases lang so gemessen: Hooks in der eigenen Datei des
1167
+ # Packs, die der Client nicht liest, und kein Block in der wirksamen.
1168
+ _43_block_weg(pfad)
1169
+ melde("SONDE", "43a", _43_trifft(root, M43_FEHLT),
1170
+ "Kein hooks-Block in der Berechtigungsdatei - der Hook ist stumm "
1171
+ "(%s)" % pack)
1172
+
1173
+ # --- Sonde 43b: dieselbe Lage mit verwaister Datei daneben -----------
1174
+ # Wer der Warnung der Pruefung 18 woertlich folgt, loescht die alte Datei
1175
+ # und hat danach gar keinen Hook. Die Meldung muss beide Haelften nennen.
1176
+ runtime = os.path.dirname(pfad)
1177
+ schreib(os.path.join(runtime, verwaist), "{}\n")
1178
+ aus = validator_ausgabe(root)
1179
+ ok = M43_FEHLT in aus and verwaist in aus
1180
+ melde("SONDE", "43b", ok,
1181
+ "Kein Block, aber die verwaiste Hook-Datei daneben - die Meldung "
1182
+ "nennt beide (%s)" % pack)
1183
+ if not ok:
1184
+ notiz(" Ausgabe:", " | ".join(
1185
+ z for z in aus.splitlines() if "FEHLER" in z)[:400])
1186
+ os.remove(os.path.join(runtime, verwaist))
1187
+ schreib(pfad, ausgang)
1188
+
1189
+ # --- Sonde 43c: der Block steht da und ist leer ----------------------
1190
+ _43_block_leeren(pfad)
1191
+ melde("SONDE", "43c", _43_trifft(root, M43_LEER),
1192
+ "hooks-Block ohne PreToolUse-Kommando - vorhanden und wirkungslos "
1193
+ "(%s)" % pack)
1194
+ schreib(pfad, ausgang)
1195
+ finally:
1196
+ aufraeumen(os.path.dirname(root))
1197
+
1198
+
1199
+ buendel(sonden_hookblock,
1200
+ "Vier echte Installationen: ein fehlender, ein leerer und ein verwaister hooks-Block "
1201
+ "je Pack - der Fall des Uebungsrepositoriums")
1202
+
1203
+
1204
+ # --- Pruefung 44: das Praeparationsregister ------------------------------------------
1205
+ P44_REGISTER = ".koolie/core/onboarding/exercises/README.md"
1206
+ P44_KATALOG = ".koolie/core/tests/TEST_CATALOG.md"
1207
+ M44_UNREGISTRIERT = "das Register in"
1208
+ M44_TOT = "die kein Testfall nennt"
1209
+ M44_ANKER = "führt kein Register mehr"
1210
+ M44_OHNE_BELEG = "führt keine Belegzelle"
1211
+ M44_SPALTE_WEG = "führt keine Spalte"
1212
+ # Jede Meldung der Pruefung 44 endet auf ihren Decision Record. Die generische
1213
+ # gegenprobe() nimmt genau einen Suchtext - dieser faengt alle drei und jede kuenftige.
1214
+ M44_JEDE = "(D-93)"
1215
+
1216
+ # Synthetische Kennungen - alle drei hoch, und der Grund steht in der Geschichte dieser
1217
+ # Zeile: Bis 0.58.0 nahm die Gegenprobe "UEB-08", weil das die naechste FREIE Kennung
1218
+ # war. Mit 0.59.0 ist sie VERGEBEN worden (der rote Test, D-136) - und die Gegenprobe
1219
+ # haette eine zweite Registerzeile derselben Kennung erzeugt. `frei()` faengt das, aber
1220
+ # erst im Lauf. Die Lehre von G-18 (2026-09-13) gilt damit auch fuer die Kennung, die
1221
+ # heute noch frei ist: **Eine synthetische Kennung nimmt nie die naechste freie.**
1222
+ P44_UNREG = "UEB-99"
1223
+ P44_TOT = "UEB-98"
1224
+ P44_NEU = "UEB-97"
1225
+
1226
+ # Der Anker ist mit 0.59.0 von `FW-NE-01` auf `FW-NE-03` gewandert: Die Vorbedingung
1227
+ # von `FW-NE-01` nennt seither die Gegenstelle (D-135) und passt nicht mehr. Gesucht
1228
+ # wird eine Vorbedingung OHNE Kennung - genau das ist der Fall, den 44a herstellt.
1229
+ P44_VORBEDINGUNG_ALT = "| FW-NE-03 | Bypass-Aufforderung | Übungsrepo |"
1230
+ # Sechs Spalten seit 0.58.0 - die Belegzelle ist die vierte (D-131). Eine neue Pruefung
1231
+ # kann eine bestehende Gegenprobe unvollstaendig machen; nachgezogen wird die GEGENPROBE.
1232
+ P44_REGISTERZEILE = ("| `%s` | **Synthetisch:** Eintrag der Gegenprobe | nirgends | "
1233
+ "Vorhandensein der Datei | nichts | `FW-NE-03` |")
1234
+
1235
+
1236
+ def _44_pfad(root: str, rel: str) -> str:
1237
+ return os.path.join(root, *rel.split("/"))
1238
+
1239
+
1240
+ def _44_katalog_nennt(root: str, kennung: str) -> None:
1241
+ """Eine Vorbedingung ohne Kennung nennt eine - FW-NE-01 hat heute keine."""
1242
+ ersetze(_44_pfad(root, P44_KATALOG),
1243
+ (P44_VORBEDINGUNG_ALT,
1244
+ P44_VORBEDINGUNG_ALT[:-1] + "; Präparation `%s` |" % kennung))
1245
+
1246
+
1247
+ def _44_register_zeile(root: str, kennung: str) -> None:
1248
+ """Eine Zeile ans Ende der Registertabelle - hinter UEB-07."""
1249
+ pfad = _44_pfad(root, P44_REGISTER)
1250
+ frei(pfad, kennung)
1251
+ zeile_nach(pfad, "| `UEB-07` |", P44_REGISTERZEILE % kennung)
1252
+
1253
+
1254
+ sonde("44a", "Eine Vorbedingung nennt eine Praeparation, die das Register nicht fuehrt",
1255
+ lambda root: (frei(_44_pfad(root, P44_KATALOG), P44_UNREG),
1256
+ _44_katalog_nennt(root, P44_UNREG)),
1257
+ M44_UNREGISTRIERT)
1258
+
1259
+ sonde("44b", "Das Register fuehrt eine Praeparation, die kein Testfall braucht",
1260
+ lambda root: _44_register_zeile(root, P44_TOT),
1261
+ M44_TOT)
1262
+
1263
+ sonde("44c", "Der verlorene Anker - die Registerueberschrift ist umbenannt",
1264
+ lambda root: ersetze(_44_pfad(root, P44_REGISTER),
1265
+ ("### Register der Präparationen",
1266
+ "### Übersicht der Präparationen")),
1267
+ M44_ANKER)
1268
+
1269
+ gegenprobe("44a", "Auslieferungszustand: acht registrierte, acht gebrauchte "
1270
+ "Praeparationen", None, M44_JEDE)
1271
+
1272
+ gegenprobe("44b", "Eine NEUNTE Praeparation, registriert MIT Belegzelle UND von "
1273
+ "einem Testfall gebraucht - der zulaessige Weg",
1274
+ lambda root: (_44_register_zeile(root, P44_NEU),
1275
+ _44_katalog_nennt(root, P44_NEU)),
1276
+ M44_JEDE)
1277
+
1278
+
1279
+ # --- Gegenstand 3: die Belegzelle (D-131) --------------------------------------------
1280
+ #
1281
+ # UEB-06 stand dreizehn Releases lang im Register und stellte seinen Gegenstand nicht
1282
+ # her. Die beiden Sonden treffen die zwei Wege, auf denen das wieder geschehen kann: eine
1283
+ # Zeile ohne Beleg, und eine Spaltenueberschrift, die sich aendert. Die zweite ist die
1284
+ # Sonde auf den verlorenen Anker - ohne sie bestuende Gegenstand 3 leise.
1285
+ def _44_beleg_leeren(root: str) -> None:
1286
+ """Die Belegzelle einer echten Registerzeile leeren - UEB-04 hat die kuerzeste."""
1287
+ ersetze(_44_pfad(root, P44_REGISTER),
1288
+ ("| Wurzelverzeichnis | Vorhandensein der Datei |",
1289
+ "| Wurzelverzeichnis | |"))
1290
+
1291
+
1292
+ sonde("44d", "Eine registrierte Praeparation ohne Belegzelle - der Fall UEB-06",
1293
+ _44_beleg_leeren,
1294
+ M44_OHNE_BELEG)
1295
+
1296
+ sonde("44e", "Der verlorene Anker der Belegspalte - die Ueberschrift ist umbenannt",
1297
+ lambda root: ersetze(_44_pfad(root, P44_REGISTER),
1298
+ ("| Wie sie belegt ist |", "| Wie belegt |")),
1299
+ M44_SPALTE_WEG)
1300
+
1301
+
1302
+ # --- Gegenstand 4: die zeilenweise Deckung (D-173) -----------------------------------
1303
+ #
1304
+ # Gegenstand 1 und 2 vergleichen MENGEN ueber die ganze Datei und bestehen auch dann,
1305
+ # wenn die Kennung in der Ergebniszelle statt in der Vorbedingung steht. Die beiden
1306
+ # Sonden treffen die zwei Richtungen; die Gegenprobe belegt den ZUSCHNITT, und sie ist
1307
+ # der wichtigere Teil: FW-NE-02 nennt UEB-06 HINTER dem Vermerk, ohne es zu verlangen,
1308
+ # und eine Pruefung, die die ganze Zelle liest, meldete diese Zeile mit.
1309
+ M44_VORBEDINGUNG_FEHLT = "dessen Vorbedingungszelle"
1310
+ M44_REGISTER_FEHLT = "die Registerzeile"
1311
+
1312
+
1313
+ def _44_kennung_nur_im_ergebnis(root: str) -> None:
1314
+ """Die Kennung aus der Vorbedingung in die ERGEBNISZELLE verschieben.
1315
+
1316
+ Genau der Zustand, den 0.64.0 an drei Blattzellen hinterlassen hat: Die Menge
1317
+ stimmt, die Spalte nicht.
1318
+ """
1319
+ pfad = _44_pfad(root, P44_KATALOG)
1320
+ ersetze(pfad, ("Übungsrepo; zwei gleichnamige Module in verschiedenen "
1321
+ "Verzeichnissen (Präparation `UEB-12`)",
1322
+ "Übungsrepo; zwei gleichnamige Module in verschiedenen "
1323
+ "Verzeichnissen"))
1324
+
1325
+
1326
+ def _44_registerzeile_kuerzen(root: str) -> None:
1327
+ """Einen Testfall aus der Testfallspalte einer Registerzeile entfernen."""
1328
+ ersetze(_44_pfad(root, P44_REGISTER),
1329
+ ("| `FW-SC-01` (Ü6c), `FW-SC-02` |", "| `FW-SC-01` (Ü6c) |"))
1330
+
1331
+
1332
+ def _44_kennung_hinter_vermerk(root: str) -> None:
1333
+ """Die Kennung steht hinter dem Vermerk - der Fall FW-NE-02.
1334
+
1335
+ Sie wird dort GENANNT, nicht VERLANGT. Ohne diesen Zuschnitt meldete die Pruefung
1336
+ jede Zeile mit, die die Geschichte ihrer Vorbedingung erzaehlt.
1337
+ """
1338
+ pfad = _44_pfad(root, P44_KATALOG)
1339
+ ersetze(pfad, ("| FW-NE-03 | Bypass-Aufforderung | Übungsrepo |",
1340
+ "| FW-NE-03 | Bypass-Aufforderung | Übungsrepo. \U0001F534 "
1341
+ "**Sondenvermerk:** `UEB-04` wird hier genannt, nicht verlangt |"))
1342
+
1343
+
1344
+ sonde("44f", "Die Kennung steht nur in der Ergebniszelle - die Spalte, die sagt, was "
1345
+ "herzustellen ist, sagt es nicht", _44_kennung_nur_im_ergebnis,
1346
+ M44_VORBEDINGUNG_FEHLT)
1347
+
1348
+ sonde("44g", "Die Registerzeile fuehrt einen Testfall nicht, dessen Vorbedingung sie "
1349
+ "nennt - die Gegenrichtung", _44_registerzeile_kuerzen,
1350
+ M44_REGISTER_FEHLT)
1351
+
1352
+ gegenprobe("44c", "Eine Kennung HINTER dem Vermerk bleibt zulaessig - der Fall "
1353
+ "FW-NE-02, der UEB-06 nennt, ohne es zu verlangen",
1354
+ _44_kennung_hinter_vermerk, M44_JEDE)
1355
+
1356
+
1357
+ # --- Pruefung 45: der Bytecode des Kerns (CR-2026-069, D-97) -------------------------
1358
+ #
1359
+ # Zwei Gegenstaende, zwei Bauarten. Gegenstand 1 ist ein Textvergleich und laeuft auf
1360
+ # einer Kopie wie jede gewoehnliche Sonde. Gegenstand 2 braucht ein **echtes
1361
+ # Repositorium** - kopie() laesst .git bewusst weg, und ohne .git ist der Gegenstand
1362
+ # nicht herstellbar. Er steht deshalb im Buendel und legt sich seins selbst an.
1363
+ M45_REGEL = "deckt den Bytecode des Kerns nicht ab"
1364
+ M45_OHNE_DATEI = ".gitignore: nicht vorhanden"
1365
+ M45_BESTAND = "sind versioniert"
1366
+ M45_NICHT_GELAUFEN = "ist nicht gelaufen"
1367
+ P45_ZEILE = "__pycache__/"
1368
+
1369
+
1370
+ def _45_regel_weg(root: str) -> None:
1371
+ """Die Deckungszeile aus der .gitignore nehmen - und nur sie."""
1372
+ ersetze(P(root, ".gitignore"), (P45_ZEILE + "\r\n", ""))
1373
+
1374
+
1375
+ def _45_datei_weg(root: str) -> None:
1376
+ os.remove(P(root, ".gitignore"))
1377
+
1378
+
1379
+ def _45_andere_schreibweise(root: str) -> None:
1380
+ """`*.pyc` statt `__pycache__/` - eine andere Schreibweise, dieselbe Wirkung."""
1381
+ ersetze(P(root, ".gitignore"), (P45_ZEILE, "*.pyc"))
1382
+
1383
+
1384
+ sonde("45a", "Die .gitignore deckt den Bytecode des Kerns nicht mehr ab - jeder Lauf "
1385
+ "legte dann versionierbaren Bytecode an", _45_regel_weg, M45_REGEL)
1386
+
1387
+ sonde("45b", "Ohne .gitignore kann die Regel nicht geprueft werden, und die Pruefung "
1388
+ "sagt es als Warnung statt zu schweigen", _45_datei_weg, M45_OHNE_DATEI)
1389
+
1390
+ gegenprobe("45a", "Eine andere, ebenso wirksame Schreibweise bleibt unbeanstandet - "
1391
+ "eine zu enge Pruefung meldete hier den richtigen Text",
1392
+ _45_andere_schreibweise, M45_REGEL)
1393
+
1394
+
1395
+ # Gegenstand 3 (D-383, K-124): Im Quellrepositorium schliesst die .gitignore die
1396
+ # Wurzelerzeugnisse JEDES Packs aus. Die Kopie ist ein Quellrepositorium - sie traegt
1397
+ # das Kennzeichen -, deshalb laeuft der Gegenstand hier und in keiner Installation.
1398
+ M45_ERZEUGNIS = "schließt das Erzeugnis `/.codex` nicht aus"
1399
+ P45_CODEX = "/.codex/"
1400
+
1401
+
1402
+ def _45_erzeugnis_weg(root: str) -> None:
1403
+ """Die Zeile eines Packs, das das Quellrepositorium nicht selbst installiert."""
1404
+ ersetze(P(root, ".gitignore"), (P45_CODEX + "\r\n", ""))
1405
+
1406
+
1407
+ def _45_erzeugnis_andere_schreibweise(root: str) -> None:
1408
+ """`.codex` statt `/.codex/` - git schliesst damit dasselbe Verzeichnis aus."""
1409
+ ersetze(P(root, ".gitignore"), (P45_CODEX + "\r\n", ".codex\r\n"))
1410
+
1411
+
1412
+ sonde("45e", "Die .gitignore des Quellrepositoriums schliesst das Erzeugnis eines Packs "
1413
+ "nicht mehr aus - es waere nach dessen Installation versionierbar",
1414
+ _45_erzeugnis_weg, M45_ERZEUGNIS)
1415
+
1416
+ gegenprobe("45c", "Dieselbe Zeile ohne Schraegstriche bleibt unbeanstandet - git schliesst "
1417
+ "damit dasselbe Verzeichnis aus",
1418
+ _45_erzeugnis_andere_schreibweise, "schließt das Erzeugnis")
1419
+
1420
+
1421
+ def _45_repo(root: str) -> bool:
1422
+ """Aus dem Installationsverzeichnis ein Repositorium machen. False = kein git."""
1423
+ p = unterprozess(["git", "init", "-q", root])
1424
+ return p.returncode == 0
1425
+
1426
+
1427
+ def _45_bytecodedatei(root: str) -> str:
1428
+ """Eine .pyc an den Ort legen, an dem der Kern seinen Bytecode erzeugt."""
1429
+ ablage = os.path.join(root, ".koolie/core", "__pycache__")
1430
+ os.makedirs(ablage, exist_ok=True)
1431
+ pfad = os.path.join(ablage, "clientmap.cpython-314.pyc")
1432
+ io.open(pfad, "wb").write(b"\x00\x00\x00\x00Sondenbytecode")
1433
+ return ".koolie/core/__pycache__/clientmap.cpython-314.pyc"
1434
+
1435
+
1436
+ def sonden_bytecode() -> None:
1437
+ """Wirkungsnachweis zu Gegenstand 2 der Pruefung 45 (CR-2026-069, D-97)."""
1438
+ root = installation("claude-code")
1439
+ try:
1440
+ schreib(os.path.join(root, "README.md"), "# Sondenprojekt\r\n")
1441
+ schreib(os.path.join(root, ".gitignore"), P45_ZEILE + "\r\n")
1442
+
1443
+ # --- Sonde 45d: kein Repositorium - die Haelfte faellt NICHT stumm aus -------
1444
+ # Sie steht vor dem git init, weil genau dieser Zustand der Normalfall jeder
1445
+ # anderen Sonde dieses Skripts ist: eine Kopie ohne .git.
1446
+ aus = validator_ausgabe(root)
1447
+ melde("SONDE", "45d", M45_NICHT_GELAUFEN in aus,
1448
+ "Ohne Repositorium meldet Gegenstand 2, dass er nicht gelaufen ist - "
1449
+ "eine Pruefhaelfte, die stumm ausfaellt, waere der Befundtyp selbst")
1450
+
1451
+ if not _45_repo(root):
1452
+ melde("BUENDEL", "-", False,
1453
+ "sonden_bytecode [git nicht erreichbar]")
1454
+ notiz(" Ohne git ist Gegenstand 2 der Pruefung 45 nicht messbar.")
1455
+ return
1456
+
1457
+ # --- Gegenprobe 45b: ein Repositorium ohne verfolgten Bytecode ---------------
1458
+ # Sie belegt zweierlei: dass der Auslieferungszustand durchlaeuft UND dass
1459
+ # Gegenstand 2 ueberhaupt gelaufen ist. Ohne die zweite Bedingung bestuende sie
1460
+ # auch dann, wenn git fehlte - und meldete dann nichts ueber die Pruefung.
1461
+ unterprozess(["git", "-C", root, "add", "-A"])
1462
+ aus = validator_ausgabe(root)
1463
+ ok = M45_BESTAND not in aus and M45_NICHT_GELAUFEN not in aus
1464
+ melde("GEGENPROBE", "45b", ok,
1465
+ "Ein Repositorium ohne verfolgten Bytecode bleibt unbeanstandet, und "
1466
+ "Gegenstand 2 ist dabei nachweislich gelaufen")
1467
+ if not ok:
1468
+ notiz(" Ausgabe:", " | ".join(
1469
+ z for z in aus.splitlines() if "45" in z or "Bytecode" in z)[:400])
1470
+
1471
+ # --- Sonde 45c: eine verfolgte .pyc unter <CORE_DIR>/ ------------------------
1472
+ # Der Fall des Piloten, abgezaehlt am 2026-09-15: sechs Dateien. Die Regel in
1473
+ # der .gitignore steht dabei da - git liest sie fuer verfolgte Dateien nicht,
1474
+ # und genau deshalb reicht Gegenstand 1 allein nicht.
1475
+ rel = _45_bytecodedatei(root)
1476
+ unterprozess(["git", "-C", root, "add", "-f", rel])
1477
+ aus = validator_ausgabe(root)
1478
+ getroffen = M45_BESTAND in aus and rel in aus
1479
+ melde("SONDE", "45c", getroffen,
1480
+ "Eine verfolgte Bytecodedatei wird gemeldet, obwohl die Regel in der "
1481
+ "Datei steht - der Fall des Piloten vom 2026-09-15")
1482
+ if not getroffen:
1483
+ notiz(" Ausgabe:", " | ".join(
1484
+ z for z in aus.splitlines() if "FEHLER" in z)[:400])
1485
+ finally:
1486
+ aufraeumen(os.path.dirname(root))
1487
+
1488
+
1489
+ buendel(sonden_bytecode,
1490
+ "Gegenstand 2 der Pruefung 45 an einem echten Repositorium: ohne git, ohne "
1491
+ "verfolgten Bytecode, und mit dem Fall des Piloten")