@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,1447 @@
1
+ """Sonden zu den Pruefungen 46 bis 55 und zur Platzhalterbindung; Selbstprobe des
2
+ Baumdurchlaufs.
3
+
4
+ Teil des Sondenskripts probe-pruefungen.py, seit 1.19.1 in Module geteilt (K-174). Die
5
+ Einheiten melden sich beim Laden dieses Moduls an; der Einstieg laedt die Module in der
6
+ Reihenfolge ihrer Nummer, und das ist die Reihenfolge der Ausgabe (D-49). Ein Modul
7
+ liest nur aus dem Apparat und aus frueheren Teilen."""
8
+ from __future__ import annotations
9
+
10
+ import glob
11
+ import json
12
+ import os
13
+ import re
14
+
15
+ from .apparat import (
16
+ aufraeumen, buendel, ersetze, ersetzt, frei, gegenprobe, installation, lies, melde,
17
+ notiz, P, Praeparationsfehler, QUELLE, schreib, sonde, strict_ausgabe,
18
+ validator_ausgabe, zeile_nach)
19
+
20
+
21
+ # --- Pruefung 46: der 1.0.0-Stand (CR-2026-070, D-98, D-99) --------------------------
22
+ #
23
+ # Sechs Sonden, je eine auf einen eigenen Gegenstand, und zwei davon fuer die zwei
24
+ # Richtungen: Ein Kriterium, das ZURUECKFAELLT, und ein Fortschritt, der NICHT
25
+ # NACHGEZOGEN ist, sind beide ein Fehler. Ohne die zweite Richtung waere der Zaehler ein
26
+ # Fortschrittsbalken - er hielte still, solange sich nichts verschlechtert, und der
27
+ # Stand stuende wieder daneben.
28
+ #
29
+ # Drei Gegenproben, und sie treffen genau die Stellen, an denen die alten Zaehlregeln zu
30
+ # breit oder zu schmal waren: ein Klaerungspunkt mit demselben Statuswort (die alte
31
+ # Regel zaehlte fuenf davon mit) und ein Marker in einem datierten Protokoll (der
32
+ # Zaehlbereich schliesst ihn aus, und das muss er auch tun).
33
+ M46_ANKER = "die Standzeile steht 0x statt genau einmal"
34
+ M46_K1 = "Kriterium 1 von D-11"
35
+ M46_K2 = "Kriterium 2 von D-11"
36
+ M46_K3 = "Kriterium 3 von D-11"
37
+ M46_K4 = "Kriterium 4 von D-11"
38
+ M46_NICHT_NACHGEZOGEN = "der Fortschritt ist nicht nachgezogen"
39
+ M46_RUECKFALL = ("entweder ist der Bestand zur\u00fcckgefallen, oder der "
40
+ "Z\u00e4hlbereich sieht erstmals")
41
+ M46_AUSSERHALB = "ausserhalb des Zaehlbereichs von Kriterium 1"
42
+ P46_ROADMAP = ".koolie/core/docs/ROADMAP.md".replace("/", os.sep)
43
+ P46_STAND = "Gezählt von Prüfung 46: Kriterium 1 = "
44
+ # Der Marker in seiner clientneutralen Form - zusammengesetzt, weil eine woertliche
45
+ # Nennung in diesem Skript selbst eine Fundstelle waere und Kriterium 1 um eins hoebe.
46
+ # Dieses Skript liegt im Zaehlbereich.
47
+ P46_MARKER = "<VERIFY AGAINST CURRENT " + "CLIENT" + " DOCUMENTATION>"
48
+
49
+
50
+ def _46_zahl_verstellen(root: str, welche: int, neu: str) -> None:
51
+ """Eine der vier Zahlen der Standzeile auf einen anderen Wert setzen."""
52
+ pfad = P(root, P46_ROADMAP)
53
+ zeilen = lies(pfad).split("\r\n")
54
+ treffer = [i for i, z in enumerate(zeilen) if P46_STAND in z]
55
+ if len(treffer) != 1:
56
+ raise Praeparationsfehler(
57
+ "ROADMAP.md: Standzeile steht %dx, erwartet genau einmal" % len(treffer))
58
+ teile = re.split(r"(= \d+)", zeilen[treffer[0]])
59
+ stellen = [i for i, s in enumerate(teile) if s.startswith("= ")]
60
+ if len(stellen) != 4:
61
+ raise Praeparationsfehler(
62
+ "ROADMAP.md: Standzeile fuehrt %d Zahlen, erwartet vier" % len(stellen))
63
+ teile[stellen[welche]] = "= " + neu
64
+ zeilen[treffer[0]] = "".join(teile)
65
+ schreib(pfad, "\r\n".join(zeilen))
66
+
67
+
68
+ def _46_standzeile_weg(root: str) -> None:
69
+ """Die Standzeile ganz entfernen - der verlorene Anker."""
70
+ pfad = P(root, P46_ROADMAP)
71
+ zeilen = lies(pfad).split("\r\n")
72
+ behalten = [z for z in zeilen if P46_STAND not in z]
73
+ if len(behalten) == len(zeilen):
74
+ raise Praeparationsfehler("ROADMAP.md: keine Standzeile gefunden")
75
+ schreib(pfad, "\r\n".join(behalten))
76
+
77
+
78
+ def _46_marker_dazu(root: str) -> None:
79
+ """Eine neue unverifizierte Aussage im Kern - Kriterium 1 steigt um eins."""
80
+ pfad = P(root, ".koolie/core/framework/core/03-security.md".replace("/", os.sep))
81
+ schreib(pfad, lies(pfad) + "\r\n> Sondenzeile: Wirkung der Sandbox je "
82
+ "Betriebssystem " + P46_MARKER + ".\r\n")
83
+
84
+
85
+ def _46_testblatt_dazu(root: str) -> None:
86
+ """Ein Testblatt an einem Ort, den eine Ablagenliste uebersaehe.
87
+
88
+ Genau der Befund, der Pruefung 46 ausgeloest hat: Die alte Regel las "die dezentralen
89
+ TESTS.md je Skill" als zwoelf Dateien, und die dreizehnte lag unter role-packs/.
90
+ Diese Sonde legt eine vierzehnte unter tech-packs/ an - eine Ablagenliste, die die
91
+ dreizehnte uebersah, uebersaehe sie ebenso.
92
+ """
93
+ ordner = P(root, ".koolie/core/framework/tech-packs/_template".replace("/", os.sep))
94
+ schreib(os.path.join(ordner, "TESTS.md"),
95
+ "# Sondentestblatt\r\n\r\n"
96
+ "| Test-ID | Ziel | Prüfmethode | Ergebnisstatus |\r\n"
97
+ "|---|---|---|---|\r\n"
98
+ "| SO-001 | Sondenfall | sitzung | offen |\r\n")
99
+
100
+
101
+ def _46_steckbrief_dazu(root: str) -> None:
102
+ """Ein neues Modul auf `entwurf` - Kriterium 3 steigt um eins."""
103
+ schreib(P(root, ".koolie/core/prompts/13-sondenprompt.md".replace("/", os.sep)),
104
+ "# Sondenprompt\r\n\r\n"
105
+ "| Attribut | Wert |\r\n|---|---|\r\n"
106
+ "| ID | `FW-PR-13` |\r\n| Version | `0.1.0` |\r\n"
107
+ "| Status | `entwurf` |\r\n| Owner (Rolle) | `<FRAMEWORK_OWNER>` |\r\n")
108
+
109
+
110
+ # Synthetische Kennung der Gegenprobe 46b. Sie stand bis 0.49.0 auf K-36 - und 0.50.0
111
+ # hat K-36 und K-37 wirklich vergeben (CR-2026-072). Der Kennungswaechter frei() hat
112
+ # die Kollision beim Sondenlauf gemeldet, statt sie als Befund am Repositorium
113
+ # erscheinen zu lassen; das ist die Lehre von G-18 (2026-09-13) zum zweiten Mal, und
114
+ # diesmal hat sie funktioniert. Die 99 folgt der Konvention von G-99 und UEB-99: hoch
115
+ # genug, dass keine echte Vergabe sie erreicht.
116
+ P46_KLAERUNG = "K-99"
117
+ P46_BESTAETIGT = "| entschieden (`CR-2026-071`); "
118
+ P46_VORSCHLAG = "| entschieden (Vorschlag); "
119
+
120
+
121
+ def _46_record_zurueckgefallen(root: str) -> None:
122
+ """D-10 auf `entschieden (Vorschlag)` zuruecksetzen - Kriterium 4 STEIGT auf eins.
123
+
124
+ Bis 0.48.0 hob diese Sonde D-10 AUS dem Vorschlagsstatus HERAUS und belegte damit
125
+ die Richtung "Fortschritt nicht nachgezogen". Mit 0.49.0 sind alle neun Records
126
+ bestaetigt (CR-2026-071, D-100) - die Hebung hat keinen Gegenstand mehr, und der
127
+ alte Suchtext haette zwar noch getroffen (er steht jetzt im Verlaufszusatz der
128
+ Zelle), aber an einer Stelle, die Pruefung 46 gar nicht liest. Eine Sonde, die
129
+ etwas veraendert, ohne den Gegenstand zu treffen, ist der schlechteste Zustand:
130
+ Der Baumvergleich meldet kein "[nichts praepariert]", und der Fehlschlag sieht aus
131
+ wie ein Befund an der Pruefung.
132
+
133
+ Die Sonde stellt ihren Defekt deshalb seither HER statt ihn zu entfernen - wie 38a
134
+ und 38b seit 0.38.0 - und deckt damit die Richtung, die vorher KEINE Sonde decken
135
+ konnte, weil Kriterium 4 nie null war: den RUECKFALL. Getroffen wird der ANFANG
136
+ der Statuszelle, denn genau das liest der Zaehler (`zellen[4].startswith`).
137
+ """
138
+ pfad = P(root, ".koolie/core/governance/DECISION_LOG.md".replace("/", os.sep))
139
+ zeilen = lies(pfad).split("\r\n")
140
+ treffer = [i for i, z in enumerate(zeilen) if z.startswith("| D-10 |")]
141
+ if len(treffer) != 1:
142
+ raise Praeparationsfehler(
143
+ "DECISION_LOG.md: Zeile D-10 steht %dx, erwartet genau einmal"
144
+ % len(treffer))
145
+ if P46_BESTAETIGT not in zeilen[treffer[0]]:
146
+ raise Praeparationsfehler(
147
+ "DECISION_LOG.md: die Statuszelle von D-10 beginnt nicht mit %r"
148
+ % P46_BESTAETIGT)
149
+ zeilen[treffer[0]] = zeilen[treffer[0]].replace(
150
+ P46_BESTAETIGT, P46_VORSCHLAG, 1)
151
+ schreib(pfad, "\r\n".join(zeilen))
152
+
153
+
154
+ def _46_klaerungspunkt_dazu(root: str) -> None:
155
+ """Ein Klaerungspunkt mit demselben Statuswort - er ist KEIN Decision Record.
156
+
157
+ Die alte Zaehlregel war ein roher grep und zaehlte fuenf solcher Zeilen mit. D-11
158
+ sagt "Decision Records"; ein Klaerungspunkt ist keiner.
159
+ """
160
+ pfad = P(root, ".koolie/core/governance/DECISION_LOG.md".replace("/", os.sep))
161
+ frei(pfad, P46_KLAERUNG)
162
+ zeile_nach(pfad, "| K-35 |",
163
+ "| " + P46_KLAERUNG + " | Sondenklärungspunkt | niedrig | Sondenlauf | "
164
+ "Framework Owner | entschieden (Vorschlag): Sondenauflösung |")
165
+
166
+
167
+ def _46_protokollmarker(root: str) -> None:
168
+ """Ein Marker in einem datierten Protokoll - ausserhalb des Zaehlbereichs.
169
+
170
+ Die Gattungsausnahme aus E2. Ein Bericht von gestern ist nicht bearbeitbar; zaehlte
171
+ er mit, stiege Kriterium 1 mit jedem Protokoll, das den Marker erwaehnt, und koennte
172
+ nie sinken.
173
+ """
174
+ ordner = P(root, ".koolie/core/tests/protocols".replace("/", os.sep))
175
+ schreib(os.path.join(ordner, "2026-09-15-sondenprotokoll.md"),
176
+ "# Sondenprotokoll\r\n\r\nGemessen: Mustersemantik " + P46_MARKER + ".\r\n")
177
+
178
+
179
+ sonde("46a", "Eine Zahl der Standzeile steht zu hoch - der Zaehler meldet den nicht "
180
+ "nachgezogenen Fortschritt", lambda r: _46_zahl_verstellen(r, 3, "99"),
181
+ M46_NICHT_NACHGEZOGEN)
182
+
183
+ sonde("46b", "Ohne Standzeile hat Pruefung 46 ihren Gegenstand verloren und sagt es, "
184
+ "statt leise zu bestehen", _46_standzeile_weg, M46_ANKER)
185
+
186
+ sonde("46c", "Eine neue unverifizierte Aussage im Kern hebt Kriterium 1, ohne dass "
187
+ "jemand die Standzeile anfasst", _46_marker_dazu, M46_K1)
188
+
189
+ sonde("46d", "Ein Testblatt an einer Ablage, die keine Liste kennt, hebt Kriterium 2 - "
190
+ "der Befund dieses Antrags", _46_testblatt_dazu, M46_K2)
191
+
192
+ sonde("46e", "Ein neues Modul auf entwurf hebt Kriterium 3, auch ausserhalb der vier "
193
+ "frueher genannten Ablagen", _46_steckbrief_dazu, M46_K3)
194
+
195
+ sonde("46f", "Ein zurueckgefallener Decision Record hebt Kriterium 4 - die Standzeile "
196
+ "steht dann zu niedrig", _46_record_zurueckgefallen, M46_RUECKFALL)
197
+
198
+ gegenprobe("46a", "Das unveraenderte Repositorium bleibt unbeanstandet - alle vier "
199
+ "Zahlen der Standzeile stimmen", None, "D-11")
200
+
201
+ gegenprobe("46b", "Ein Klaerungspunkt mit demselben Statuswort bleibt ungezaehlt - "
202
+ "die alte Regel zaehlte fuenf davon mit", _46_klaerungspunkt_dazu,
203
+ M46_K4)
204
+
205
+ gegenprobe("46c", "Ein Marker in einem datierten Protokoll bleibt ungezaehlt - ein "
206
+ "Bericht von gestern ist nicht bearbeitbar", _46_protokollmarker,
207
+ M46_K1)
208
+
209
+
210
+ # --- 46g, 46h, Gegenprobe 46d (K-98, D-483): die Markerform ausserhalb des Zaehlbereichs
211
+ #
212
+ # Kriterium 1 zaehlt den Kern. Die Wurzeldokumente und die Quellen des Hauptdokuments
213
+ # liegen ausserhalb; seit 1.19.1 meldet Pruefung 46 dort jede Fundstelle einzeln, ohne
214
+ # die Zaehlung zu veraendern. Die Gegenprobe haelt die Grenze zur anderen Seite: Eine
215
+ # Wurzeldatei, die kein Einstiegsdokument ist, gehoert nicht zu diesem Gegenstand.
216
+ def _46_marker_in(rel: str):
217
+ def praeparieren(root: str) -> None:
218
+ pfad = P(root, rel.replace("/", os.sep))
219
+ if not os.path.isfile(pfad):
220
+ raise Praeparationsfehler("Sonde 46: %s fehlt" % rel)
221
+ schreib(pfad, lies(pfad) + "\r\nSondenzeile: " + P46_MARKER + "\r\n")
222
+ return praeparieren
223
+
224
+
225
+ def _46_marker_neben_der_wurzel(root: str) -> None:
226
+ schreib(P(root, "SONDENNOTIZ.txt"), "Sondenzeile: " + P46_MARKER + "\r\n")
227
+
228
+
229
+ sonde("46g", "Die Markerform in der README der Wurzel wird gemeldet, obwohl sie ausserhalb "
230
+ "des Zaehlbereichs von Kriterium 1 liegt", _46_marker_in("README.md"),
231
+ M46_AUSSERHALB)
232
+
233
+ sonde("46h", "Die Markerform in einer Quelle des Hauptdokuments unter build/doc wird "
234
+ "gemeldet", _46_marker_in(".koolie/core/build/doc/32-abschluss.md"),
235
+ M46_AUSSERHALB)
236
+
237
+ gegenprobe("46d", "Die Markerform in einer Wurzeldatei, die kein Einstiegsdokument ist, "
238
+ "gehoert nicht zu diesem Gegenstand", _46_marker_neben_der_wurzel,
239
+ M46_AUSSERHALB)
240
+
241
+
242
+ # --- Selbstprobe C1: der Baumdurchlauf sieht mehr als die Mustersuche ----------------
243
+ #
244
+ # ANLASS: Die erste Fassung des Zaehlers lief ueber glob.glob(..., recursive=True).
245
+ # glob ueberspringt Pfadbestandteile, die mit einem Punkt beginnen - damit fehlten
246
+ # fuenfzehn Dateien des Kerns, darunter genau die zwei Traeger
247
+ # clients/*/root-template/.devin/README.md und .../.claude/README.md, die den Befund zu
248
+ # Kriterium 1 tragen. Der Zaehler haette 27 gemeldet und damit zufaellig die geglaubte
249
+ # Zahl bestaetigt.
250
+ #
251
+ # Eine Zaehlregel, die einen Traeger still ueberspringt, war der ANLASS dieses Antrags.
252
+ # Sie ist beim Bauen der Abhilfe ein zweites Mal entstanden - und eine benannte Falle,
253
+ # in die man zweimal tritt, gehoert in den Code (D-74). Diese Probe zaehlt beide
254
+ # Verfahren auf dem echten Baum gegeneinander ab: Findet glob genauso viel wie os.walk,
255
+ # ist entweder der Bestand ohne versteckte Traeger - dann sagt sie das - oder jemand hat
256
+ # den Zaehler zurueckgebaut.
257
+ #
258
+ # GRENZE: Sie misst den Bestand dieses Repositoriums, nicht den eines beliebigen. In
259
+ # einem Projekt ohne versteckte Kerndateien ist der Unterschied null, und dann belegt
260
+ # sie nichts - das steht dann in ihrer eigenen Meldung.
261
+ def selbstprobe_baumdurchlauf() -> None:
262
+ """glob gegen os.walk auf dem echten Kern - der Fallstrick aus CR-2026-070 E7."""
263
+ kern = os.path.join(QUELLE, ".koolie/core")
264
+ mit_glob = {p for p in glob.glob(os.path.join(kern, "**", "*"), recursive=True)
265
+ if os.path.isfile(p)}
266
+ mit_walk = set()
267
+ for ordner, _, dateien in os.walk(kern):
268
+ for name in dateien:
269
+ mit_walk.add(os.path.join(ordner, name))
270
+ versteckt = sorted(mit_walk - mit_glob)
271
+ melde("SELBSTPROBE", "C1", bool(versteckt),
272
+ "Der Baumdurchlauf des Zaehlers findet %d Kerndateien, die eine Mustersuche "
273
+ "ueberspringt" % len(versteckt))
274
+ if not versteckt:
275
+ notiz(" glob und os.walk finden dasselbe. Entweder traegt der Kern keine "
276
+ "versteckte Datei mehr - dann belegt diese Probe nichts -, oder der "
277
+ "Zaehler ist auf glob zurueckgebaut worden (CR-2026-070 E7).")
278
+ else:
279
+ for pfad in versteckt[:3]:
280
+ notiz(" " + os.path.relpath(pfad, QUELLE).replace(os.sep, "/"))
281
+
282
+
283
+ buendel(selbstprobe_baumdurchlauf,
284
+ "Zaehlt Mustersuche gegen Baumdurchlauf auf dem echten Kern - der Fallstrick, "
285
+ "der beim Bauen von Pruefung 46 zuschnappte")
286
+
287
+ # --- 47: das Statusvokabular jedes Modultraegers ------------------------------------
288
+ #
289
+ # Die vier Gegenstaende der Pruefung, je eine Sonde - und dazu die Sonde auf den
290
+ # verlorenen Anker. Drei der vier Sonden legen eine NEUE Datei an, statt eine
291
+ # bestehende zu verstellen: Der Statuswert des Bestands bewegt sich mit jedem Release,
292
+ # und eine Sonde, die einen Wert woertlich sucht, misst ab dem naechsten Statuswechsel
293
+ # den Suchtext statt die Pruefung (die Lehre von 46f, 0.49.0).
294
+ M47_FEHLT = "der Steckbrief führt keine Zeile"
295
+ M47_VOKABULAR = "gehört nicht zum Vokabular"
296
+ M47_VORLAGE_ECHT = "die Statuszelle einer Vorlage trägt den echten Wert"
297
+ M47_SCHLITZ_FREMD = "trägt den Ausfüllschlitz"
298
+ M47_ANKER = "kein einziger Steckbrief gefunden"
299
+ P47_STECKBRIEFKOPF = "| Attribut | Wert |"
300
+ P47_SKILLVORLAGE = ".koolie/core/templates/SKILL_TEMPLATE.md".replace("/", os.sep)
301
+ P47_SCHLITZ = "<TBD: Status; ein neuer Skill beginnt auf entwurf>"
302
+
303
+
304
+ def _47_datei(root: str, name: str, statuszeile: str) -> None:
305
+ """Eine neue Prompt-Datei mit Steckbrief und der uebergebenen Statuszeile.
306
+
307
+ Eine leere Statuszeile heisst: kein Status im Steckbrief.
308
+ """
309
+ schreib(P(root, (".koolie/core/prompts/" + name).replace("/", os.sep)),
310
+ "# Sondenvorlage\r\n\r\n"
311
+ + P47_STECKBRIEFKOPF + "\r\n|---|---|\r\n"
312
+ "| ID | `FW-PR-013` |\r\n| Version | `0.1.0` |\r\n"
313
+ + (statuszeile + "\r\n" if statuszeile else "")
314
+ + "| Owner (Rolle) | `<FRAMEWORK_OWNER>` |\r\n")
315
+
316
+
317
+ def _47_ohne_statuszeile(root: str) -> None:
318
+ """Ein Steckbrief ohne Statuszeile - genau die zwoelf Traeger aus K-36."""
319
+ _47_datei(root, "13-sonde-ohne-status.md", "")
320
+
321
+
322
+ def _47_fremdes_wort(root: str) -> None:
323
+ """Ein Statuswert ausserhalb des Vokabulars - bis 0.50.0 nur in einer SKILL.md gefangen."""
324
+ _47_datei(root, "13-sonde-vokabular.md", "| Status | `banane` |")
325
+
326
+
327
+ def _47_schlitz_ausserhalb(root: str) -> None:
328
+ """Ein Ausfuellschlitz in einer Datei, die keine Vorlage ist - der Preis aus D-104."""
329
+ _47_datei(root, "13-sonde-schlitz.md",
330
+ "| Status | `<TBD: Status; ein neuer Prompt beginnt auf entwurf>` |")
331
+
332
+
333
+ def _47_vorlage_mit_echtem_wert(root: str) -> None:
334
+ """Der Defekt von 0.50.0, wiederhergestellt: eine Vorlage traegt `entwurf`.
335
+
336
+ Die Statuszelle der Skillvorlage gab diesen Wert an jede Kopie weiter und durfte
337
+ sich deshalb nie aendern; genau daran war Kriterium 3 von D-11 unerreichbar
338
+ (D-104). Die Sonde stellt den Zustand HER statt ihn zu entfernen - wie 38a, 38b
339
+ und 46f.
340
+ """
341
+ ersetze(P(root, P47_SKILLVORLAGE), (P47_SCHLITZ, "entwurf"))
342
+
343
+
344
+ def _47_steckbriefkopf_umbenennen(root: str) -> None:
345
+ """Die Kopfzeile jedes Steckbriefs umbenennen - die Pruefung findet keinen mehr.
346
+
347
+ Anders als bei den Pruefungen 28, 29, 31, 40 und 46 ist der Anker hier keine
348
+ einzelne Zeichenkette in einer Datei, sondern eine KONVENTION ueber den ganzen
349
+ Bestand. Verliert sie sich, faende die Pruefung nichts mehr und bestuende leise -
350
+ deshalb benennt diese Sonde sie ueberall um und belegt, dass der Lauf das meldet.
351
+ """
352
+ getroffen = 0
353
+ for ordner, _, dateien in os.walk(P(root, ".koolie/core")):
354
+ for name in sorted(dateien):
355
+ if not name.endswith(".md"):
356
+ continue
357
+ pfad = os.path.join(ordner, name)
358
+ text = lies(pfad)
359
+ if P47_STECKBRIEFKOPF not in text:
360
+ continue
361
+ schreib(pfad, text.replace(P47_STECKBRIEFKOPF, "| Merkmal | Wert |"))
362
+ getroffen += 1
363
+ if getroffen < 50:
364
+ raise Praeparationsfehler(
365
+ "nur %d Dateien mit der Steckbriefkopfzeile gefunden, erwartet mindestens "
366
+ "50 - die Konvention hat sich geaendert" % getroffen)
367
+
368
+
369
+ def _47_verlaufszusatz(root: str) -> None:
370
+ """Einem gehobenen Traeger einen Verlaufszusatz in Klammern anhaengen.
371
+
372
+ `entwurf (Referenzpack der Erstfassung)` steht seit der Erstfassung im Bestand;
373
+ verglichen wird deshalb das ERSTE WORT. Die Gegenprobe belegt, dass ein solcher
374
+ Zusatz zulaessig bleibt - und dass Pruefung 46 ihn weiterhin richtig einordnet.
375
+ """
376
+ ersetze(P(root, ".koolie/core/checklists/01-preflight.md".replace("/", os.sep)),
377
+ ("| Status | `pilot` |", "| Status | `pilot (Abnahme CR-2026-073)` |"))
378
+
379
+
380
+ def _47_tabelle_hinter_ueberschrift(root: str) -> None:
381
+ """Eine Steckbriefkopfzeile im KOERPER einer Datei ist kein Steckbrief.
382
+
383
+ Der Fall von templates/PLAN_TEMPLATE.md: Dort steht die Tabelle hinter einer
384
+ Ueberschrift der Ebene 2 und ist das Formular fuer die Kopie, nicht der Steckbrief
385
+ der Datei. Eine Erkennungsregel, die bloss nach der Kopfzeile sucht, verlangte dort
386
+ einen Statuswert - und die Datei fuehrt zu Recht keinen.
387
+ """
388
+ schreib(P(root, ".koolie/core/examples/example-sondenformular.md"
389
+ .replace("/", os.sep)),
390
+ "# Beispielformular (synthetisch)\r\n\r\n"
391
+ "Ein Formular, das die Kopie ausfuellt - kein Steckbrief.\r\n\r\n"
392
+ "## Formular\r\n\r\n"
393
+ + P47_STECKBRIEFKOPF + "\r\n|---|---|\r\n"
394
+ "| Erstellt mit | `<Skill>` |\r\n| Bestaetigt durch | `<Rolle>` |\r\n")
395
+
396
+
397
+ sonde("47a", "Ein Steckbrief ohne Statuszeile wird gemeldet - das Loch, durch das bis "
398
+ "0.50.0 zwoelf Traeger entkamen", _47_ohne_statuszeile, M47_FEHLT)
399
+
400
+ sonde("47b", "Ein Statuswert ausserhalb des Vokabulars faellt auf, auch weit weg von "
401
+ "einer SKILL.md", _47_fremdes_wort, M47_VOKABULAR)
402
+
403
+ sonde("47c", "Eine Vorlage mit echtem Statuswert wird gemeldet - der Defekt, der "
404
+ "Kriterium 3 unerreichbar machte", _47_vorlage_mit_echtem_wert,
405
+ M47_VORLAGE_ECHT)
406
+
407
+ sonde("47d", "Ein Ausfuellschlitz ausserhalb einer Vorlage wird gemeldet - die "
408
+ "kopierte und nicht gefuellte Vorlage", _47_schlitz_ausserhalb,
409
+ M47_SCHLITZ_FREMD)
410
+
411
+ sonde("47e", "Ohne die Steckbriefkonvention hat Pruefung 47 ihren Gegenstand verloren "
412
+ "und sagt es, statt leise zu bestehen", _47_steckbriefkopf_umbenennen,
413
+ M47_ANKER)
414
+
415
+ gegenprobe("47a", "Das unveraenderte Repositorium bleibt unbeanstandet - jeder "
416
+ "Steckbrief traegt einen gueltigen Statuswert", None, "Vokabular")
417
+
418
+ gegenprobe("47b", "Ein Verlaufszusatz in Klammern bleibt zulaessig - verglichen wird "
419
+ "das erste Wort des Werts", _47_verlaufszusatz, M47_VOKABULAR)
420
+
421
+ gegenprobe("47c", "Eine Steckbriefkopfzeile hinter einer Ueberschrift ist kein "
422
+ "Steckbrief und verlangt keinen Status", _47_tabelle_hinter_ueberschrift,
423
+ M47_FEHLT)
424
+
425
+
426
+ # --- 48: die Werkzeugneutralitaet des Kerns -----------------------------------------
427
+ #
428
+ # Die drei Gruende, aus denen Pruefung 12 die siebzehn Fundstellen nicht fand, sind hier
429
+ # je eine Sonde: der Pfad des INSTALLIERTEN Packs (Grund 2 - er existiert und war damit
430
+ # unsichtbar), der Pfad OHNE Backticks (Grund 1) und die anweisende Spalte des
431
+ # Testkatalogs, deren letzte Zelle bewusst ausgenommen ist. Dazu die Sonde auf den
432
+ # verlorenen Anker und drei Gegenproben - die Belegspalte, die Chronik und der
433
+ # unberuehrte Bestand.
434
+ #
435
+ # Die Sonden legen NEUE Dateien an, statt bestehende zu verstellen: Ein Suchtext im
436
+ # Bestand misst ab dem naechsten Release den Suchtext statt die Pruefung (die Lehre von
437
+ # 46f). Welchen Pfad sie schreiben, LESEN sie aus den Manifesten - eine Sonde, die einen
438
+ # Pfad raet, misst den geratenen Pfad.
439
+ M48_PFAD = "gehört der Laufzeitschicht des Client Packs"
440
+ M48_ANKER = "kein Client Pack mit runtime_placeholders gefunden"
441
+ P48_KATALOG = ".koolie/core/tests/TEST_CATALOG.md".replace("/", os.sep)
442
+ P48_ROADMAP = ".koolie/core/docs/ROADMAP.md".replace("/", os.sep)
443
+ P48_KATALOGANKER = "| FW-AK-02 (Basis) |"
444
+ P48_ROADMAPANKER = "#### Der Releaseplan bis 1.0.0 und darüber hinaus"
445
+
446
+
447
+ def _48_marken(root: str) -> tuple:
448
+ """(Laufzeitschicht des installierten Packs, die des anderen) - aus den Manifesten.
449
+
450
+ Installiert ist das Pack, dessen Laufzeitverzeichnis im Baum wirklich liegt; genau
451
+ darauf beruht der zweite Grund, aus dem Pruefung 12 blind war.
452
+ """
453
+ base = P(root, ".koolie/core", "clients")
454
+ verzeichnisse = []
455
+ for name in sorted(os.listdir(base)):
456
+ if name.startswith("_"):
457
+ continue
458
+ mp = os.path.join(base, name, "manifest.json")
459
+ if os.path.exists(mp):
460
+ verzeichnisse.append(json.loads(lies(mp))["runtime_dir"])
461
+ if len(verzeichnisse) < 2:
462
+ raise Praeparationsfehler(
463
+ "Weniger als zwei Client Packs mit manifest.json - die Sonden zu 48 "
464
+ "brauchen ein installiertes und ein nicht installiertes Pack")
465
+ installiert = [v for v in verzeichnisse if os.path.isdir(P(root, *v.split("/")))]
466
+ fremd = [v for v in verzeichnisse if v not in installiert]
467
+ if not installiert or not fremd:
468
+ raise Praeparationsfehler(
469
+ "Im Baum liegt keine oder jede Laufzeitschicht (%s) - die Sonden zu 48 "
470
+ "unterscheiden das installierte vom nicht installierten Pack"
471
+ % ", ".join(verzeichnisse))
472
+ return installiert[0], fremd[0]
473
+
474
+
475
+ def _48_datei(root: str, name: str, inhalt: str) -> None:
476
+ """Eine neue Prompt-Datei mit vollstaendigem Steckbrief und der Inhaltszeile."""
477
+ schreib(P(root, (".koolie/core/prompts/" + name).replace("/", os.sep)),
478
+ "# Sondenvorlage\r\n\r\n"
479
+ "| Attribut | Wert |\r\n|---|---|\r\n"
480
+ "| ID | `FW-PR-014` |\r\n| Version | `0.1.0` |\r\n"
481
+ "| Status | `pilot` |\r\n"
482
+ "| Owner (Rolle) | `<FRAMEWORK_OWNER>` |\r\n\r\n"
483
+ + inhalt + "\r\n")
484
+
485
+
486
+ def _48_installiertes_pack(root: str) -> None:
487
+ """Der Pfad des INSTALLIERTEN Packs in einem Kerntraeger - Grund 2 der Blindheit.
488
+
489
+ Pruefung 12 meldet nur Pfade, die es NICHT GIBT. Dieser hier existiert im Baum und
490
+ lief deshalb sechsundfuenfzig Releases lang durch.
491
+ """
492
+ installiert, _ = _48_marken(root)
493
+ _48_datei(root, "14-sonde-installiert.md",
494
+ "Ausgabeformat: Analyse nach `%s/skills/fw-repo-analyze/SKILL.md`."
495
+ % installiert)
496
+
497
+
498
+ def _48_ohne_backticks(root: str) -> None:
499
+ """Derselbe Befund ohne Backticks - Grund 1 der Blindheit.
500
+
501
+ Zehn der siebzehn Fundstellen standen so: im Codeblock, in Prosa oder im
502
+ HTML-Kommentar. Die Heuristik von Pruefung 12 sieht nur Token in Backticks.
503
+ """
504
+ _, fremd = _48_marken(root)
505
+ _48_datei(root, "14-sonde-prosa.md",
506
+ "Die Regeln liegen unter %s/rules und werden bei Sitzungsbeginn geladen."
507
+ % fremd)
508
+
509
+
510
+ def _48_anweisende_spalte(root: str) -> None:
511
+ """Ein Clientpfad in einer ANWEISENDEN Spalte des Testkatalogs wird gemeldet.
512
+
513
+ Die Ausnahme dieses Traegers gilt der LETZTEN Zelle (Ergebnisstatus, D-117). Wer
514
+ sie auf die Zeile ausdehnt, nimmt genau die Eingabezelle mit heraus, in der bis
515
+ 0.56.2 'Passe AGENTS.md an' stand - der Zuschnitt, der den Gegenstand mitentfernt.
516
+ """
517
+ installiert, _ = _48_marken(root)
518
+ zeile_nach(P(root, P48_KATALOG), P48_KATALOGANKER,
519
+ "| FW-SO-01 | Sondenzeile | Sondenvorbedingung | Anweisung: lies %s/config "
520
+ "| Ablehnung | Zugriff | sitzung | offen |" % installiert)
521
+
522
+
523
+ def _48_anker_verlieren(root: str) -> None:
524
+ """Ohne runtime_placeholders in den Manifesten hat die Pruefung keine Marken mehr.
525
+
526
+ Sie leitet sie von dort ab; geht der Schluessel verloren, faende sie nichts und
527
+ bestuende leise. Die Sonde belegt, dass sie das Fehlen selbst meldet (D-23).
528
+ """
529
+ base = P(root, ".koolie/core", "clients")
530
+ getroffen = 0
531
+ for name in sorted(os.listdir(base)):
532
+ mp = os.path.join(base, name, "manifest.json")
533
+ if not os.path.exists(mp):
534
+ continue
535
+ ersetze(mp, ('"runtime_placeholders"', '"runtime_placeholders_alt"'))
536
+ getroffen += 1
537
+ if not getroffen:
538
+ raise Praeparationsfehler(
539
+ "Kein manifest.json unter clients/ - die Ankersonde zu 48 haette nichts "
540
+ "zu verstellen")
541
+
542
+
543
+ def _48_belegspalte(root: str) -> None:
544
+ """Ein Clientpfad in der LETZTEN Zelle einer Testkatalogzeile bleibt zulaessig.
545
+
546
+ Der Ergebnisstatus nennt, was ein Lauf gelesen hat, und das gemessene Client Pack
547
+ (D-117). Ein Begriff statt des Pfads waere dort kein Beleg mehr.
548
+ """
549
+ _, fremd = _48_marken(root)
550
+ zeile_nach(P(root, P48_KATALOG), P48_KATALOGANKER,
551
+ "| FW-SO-02 | Sondenzeile | Sondenvorbedingung | Anweisung | Ablehnung "
552
+ "| Zugriff | sitzung | bestanden (`.koolie/core/tests/protocols/2026-09-19-testblaetter-buendel-3.md`; Client Pack `claude-code` 2.1.278 - der Lauf benennt `%s/rules/00-framework-core.md`) |"
553
+ % fremd)
554
+
555
+
556
+ def _48_chronik(root: str) -> None:
557
+ """Ein Clientpfad in der Roadmap bleibt zulaessig - sie berichtet Erhebungen.
558
+
559
+ Dieselbe Begruendung wie bei den Protokollen: Wer einen Befundbericht glaettet,
560
+ macht aus einer richtigen Zeile eine unbelegbare.
561
+ """
562
+ installiert, fremd = _48_marken(root)
563
+ pfad = P(root, P48_ROADMAP)
564
+ schreib(pfad, lies(pfad).rstrip("\r\n") + "\r\n\r\n"
565
+ + "Sondennachtrag zur Erhebung: Der Lauf las %s/rules und legte seine "
566
+ "Ausgabe unter %s/skills ab.\r\n" % (installiert, fremd))
567
+
568
+
569
+ sonde("48a", "Der Pfad des INSTALLIERTEN Packs in einem Kerntraeger wird gemeldet - "
570
+ "genau der Fall, den Pruefung 12 nie sah", _48_installiertes_pack, M48_PFAD)
571
+
572
+ sonde("48b", "Ein Clientpfad ohne Backticks wird gemeldet - zehn der siebzehn "
573
+ "Fundstellen standen so", _48_ohne_backticks, M48_PFAD)
574
+
575
+ sonde("48c", "Ein Clientpfad in einer anweisenden Spalte des Testkatalogs wird "
576
+ "gemeldet, obwohl die letzte Zelle ausgenommen ist", _48_anweisende_spalte,
577
+ M48_PFAD)
578
+
579
+ sonde("48d", "Ohne runtime_placeholders in den Manifesten meldet Pruefung 48 den "
580
+ "verlorenen Gegenstand, statt leise zu bestehen", _48_anker_verlieren,
581
+ M48_ANKER)
582
+
583
+ gegenprobe("48a", "Das unveraenderte Repositorium bleibt unbeanstandet - die siebzehn "
584
+ "Fundstellen sind aufgeloest", None, M48_PFAD)
585
+
586
+ gegenprobe("48b", "Ein Clientpfad in der Ergebnisstatuszelle des Testkatalogs bleibt "
587
+ "zulaessig - dort ist er der Beleg", _48_belegspalte, M48_PFAD)
588
+
589
+ gegenprobe("48c", "Ein Clientpfad in der Roadmap bleibt zulaessig - sie fuehrt die "
590
+ "Erhebungen je Arbeitspaket", _48_chronik, M48_PFAD)
591
+
592
+
593
+ # --- Pruefung 49: ausdruecklicher Skill-Aufruf im Testkatalog (D-146) --------------
594
+ #
595
+ # Der Befund, der sie veranlasst hat, ist am 2026-09-18 an FW-SC-01 gemessen worden: Der
596
+ # Hauptlauf rief `fw-change-small` auf, wurde abgewiesen - neun von zwoelf Kernskills
597
+ # fuehren `triggers` ohne `- model`, und das Pack claude-code bildet das auf
598
+ # `disable-model-invocation: true` ab - und arbeitete den Ablauf nicht nach. Damit fiel
599
+ # Schritt 3 des Skills aus, der die Verwender der geaenderten Einheit erhebt; die
600
+ # Scope-Falle konnte nicht zuschnappen. Die Zelle stand danach als `offen`, und die
601
+ # Ursache wurde einer Regelkollision zugeschrieben, die es nicht gibt (CR-2026-085).
602
+ M49_AUFRUF = "ohne den ausdrücklichen Aufruf"
603
+ M49_ANKER = "kein Skill mit 'triggers' ohne '- model' gefunden"
604
+ P49_KATALOG = ".koolie/core/tests/TEST_CATALOG.md".replace("/", os.sep)
605
+ P49_KATALOGANKER = "| FW-AK-02 (Basis) |"
606
+ P49_SKILLS = ".koolie/core/framework/skills".replace("/", os.sep)
607
+
608
+
609
+ def _49_skill_ohne_modell(root: str) -> str:
610
+ """Ein Kernskill, dessen Quelle `triggers` ohne `- model` fuehrt - abgeleitet.
611
+
612
+ Die Sonde raet den Namen nicht: Waere er gepflegt, prueften Sonde und Pruefung
613
+ verschiedene Mengen, und die Sonde bestuende an einem Skill, den es nicht mehr gibt.
614
+ """
615
+ basis = P(root, *P49_SKILLS.split(os.sep))
616
+ for name in sorted(os.listdir(basis)):
617
+ pfad = os.path.join(basis, name, "SKILL.md")
618
+ if not os.path.isfile(pfad):
619
+ continue
620
+ text = lies(pfad)
621
+ i = text.find("triggers:")
622
+ if i < 0:
623
+ continue
624
+ block = text[i:text.find("---", 3)] if text.startswith("---") else text[i:i + 200]
625
+ # Seit 1.17.0 tragen fw-bugfix-prepare und fw-plan `model` (D-451); der naechste
626
+ # Skill ohne model fuehrt Test- und Lintbefehle aus, und Pruefung 49 verlangt dann
627
+ # zu Recht den Schlitz in der Vorbedingung - gemessen wuerde die falsche Regel.
628
+ if "- model" not in block and "<TEST_COMMAND>" not in text and "<LINT_COMMAND>" not in text:
629
+ return name
630
+ raise Praeparationsfehler(
631
+ "Kein Kernskill mit `triggers` ohne `- model` - die Sonden zu 49 brauchen einen")
632
+
633
+
634
+ def _49_skill_mit_modell(root: str) -> str:
635
+ """Das Gegenstueck: ein Skill, den das Modell von sich aus waehlen darf."""
636
+ basis = P(root, *P49_SKILLS.split(os.sep))
637
+ for name in sorted(os.listdir(basis)):
638
+ pfad = os.path.join(basis, name, "SKILL.md")
639
+ if not os.path.isfile(pfad):
640
+ continue
641
+ text = lies(pfad)
642
+ i = text.find("triggers:")
643
+ if i < 0:
644
+ continue
645
+ block = text[i:text.find("---", 3)] if text.startswith("---") else text[i:i + 200]
646
+ if "- model" in block:
647
+ return name
648
+ raise Praeparationsfehler(
649
+ "Kein Kernskill mit `- model` - die Gegenprobe zu 49 braucht einen")
650
+
651
+
652
+ def _49_katalogzeile(root: str, zeile: str) -> None:
653
+ zeile_nach(P(root, P49_KATALOG), P49_KATALOGANKER, zeile)
654
+
655
+
656
+ def _49_nackte_nennung(root: str) -> None:
657
+ """Der Skillname ohne Schraegstrich im Ausloeser eines `sitzung`-Testfalls.
658
+
659
+ Genau die Schreibweise, in der vier Katalogzeilen ihn bis 0.59.1 fuehrten - und in
660
+ der der Prompt zu FW-SC-01 ihn gar nicht fuehrte.
661
+ """
662
+ _49_katalogzeile(root,
663
+ "| FW-SO-03 | Sondenzeile | Sondenvorbedingung | %s mit Sondenaufgabe "
664
+ "| Ablehnung | Zugriff | sitzung | offen |" % _49_skill_ohne_modell(root))
665
+
666
+
667
+ def _49_anker_verlieren(root: str) -> None:
668
+ """Ohne `triggers` in den Skillquellen hat Pruefung 49 keine Marken mehr.
669
+
670
+ Sie leitet sie von dort ab; geht der Schluessel verloren, faende sie nichts und
671
+ bestuende leise. Die Sonde belegt, dass sie das Fehlen selbst meldet (D-23).
672
+ """
673
+ basis = P(root, *P49_SKILLS.split(os.sep))
674
+ getroffen = 0
675
+ for name in sorted(os.listdir(basis)):
676
+ pfad = os.path.join(basis, name, "SKILL.md")
677
+ if not os.path.isfile(pfad):
678
+ continue
679
+ if "triggers:" in lies(pfad):
680
+ ersetze(pfad, ("triggers:", "ladeausloeser:"))
681
+ getroffen += 1
682
+ if not getroffen:
683
+ raise Praeparationsfehler(
684
+ "Keine SKILL.md mit `triggers` - die Ankersonde zu 49 haette nichts zu "
685
+ "verstellen")
686
+
687
+
688
+ def _49_ausdruecklicher_aufruf(root: str) -> None:
689
+ """Derselbe Skill als `/name` bleibt zulaessig - das ist der Aufruf selbst."""
690
+ _49_katalogzeile(root,
691
+ "| FW-SO-04 | Sondenzeile | Sondenvorbedingung | `/%s` mit Sondenaufgabe "
692
+ "| Ablehnung | Zugriff | sitzung | bestanden (Sondenbeleg, `.koolie/core/tests/protocols/2026-09-19-testblaetter-buendel-3.md`; Client Pack `claude-code` 2.1.278) |"
693
+ % _49_skill_ohne_modell(root))
694
+
695
+
696
+ def _49_modellaufrufbar(root: str) -> None:
697
+ """Ein Skill MIT `- model` bleibt nackt zulaessig - der Zuschnitt ist nicht zu breit.
698
+
699
+ Ohne dieses Paar meldete die Pruefung jeden Skillnamen und waere eine Stilregel.
700
+ """
701
+ _49_katalogzeile(root,
702
+ "| FW-SO-05 | Sondenzeile | Sondenvorbedingung | %s mit Sondenaufgabe "
703
+ "| Ablehnung | Zugriff | sitzung | bestanden (Sondenbeleg, `.koolie/core/tests/protocols/2026-09-19-testblaetter-buendel-3.md`; Client Pack `claude-code` 2.1.278) |"
704
+ % _49_skill_mit_modell(root))
705
+
706
+
707
+ def _49_andere_spalte(root: str) -> None:
708
+ """Derselbe Name in einer ANDEREN Spalte bleibt zulaessig - die Regel gilt dem Ausloeser.
709
+
710
+ Das Gegenstueck zur Spaltenaufloesung: Wer die Zeile statt der Spalte nimmt, meldet
711
+ auch die Zelle, die das erwartete Verhalten beschreibt - und dort ist die Nennung
712
+ eine Aussage ueber den Lauf, keine Anweisung an ihn.
713
+ """
714
+ _49_katalogzeile(root,
715
+ "| FW-SO-06 | Sondenzeile | Sondenvorbedingung | Sondenaufgabe "
716
+ "| Der Lauf nennt %s als zustaendig | Zugriff | sitzung | bestanden (Sondenbeleg, `.koolie/core/tests/protocols/2026-09-19-testblaetter-buendel-3.md`; Client Pack `claude-code` 2.1.278) |"
717
+ % _49_skill_ohne_modell(root))
718
+
719
+
720
+ def _49_andere_pruefmethode(root: str) -> None:
721
+ """Eine nackte Nennung bei Pruefmethode `review` bleibt zulaessig.
722
+
723
+ Die Regel gilt dem Lauf, nicht dem Lesen: Eine Durchsicht ruft keinen Skill auf.
724
+ """
725
+ _49_katalogzeile(root,
726
+ "| FW-SO-07 | Sondenzeile | Sondenvorbedingung | %s mit Sondenaufgabe "
727
+ "| Ablehnung | Zugriff | review | bestanden (Sondenbeleg, `.koolie/core/tests/protocols/2026-09-19-testblaetter-buendel-3.md`; Client Pack `claude-code` 2.1.278) |"
728
+ % _49_skill_ohne_modell(root))
729
+
730
+
731
+ sonde("49a", "Ein Kernskill ohne Modellzulassung, im Ausloeser eines sitzung-Testfalls "
732
+ "nackt genannt, wird gemeldet", _49_nackte_nennung, M49_AUFRUF)
733
+
734
+ sonde("49b", "Ohne `triggers` in den Skillquellen meldet Pruefung 49 den verlorenen "
735
+ "Gegenstand, statt leise zu bestehen", _49_anker_verlieren, M49_ANKER)
736
+
737
+ gegenprobe("49a", "Das unveraenderte Repositorium bleibt unbeanstandet - die vier "
738
+ "Fundstellen sind auf `/name` gestellt", None, M49_AUFRUF)
739
+
740
+ gegenprobe("49b", "Derselbe Skill als `/name` bleibt zulaessig - das ist der Aufruf",
741
+ _49_ausdruecklicher_aufruf, M49_AUFRUF)
742
+
743
+ gegenprobe("49c", "Ein Skill MIT Modellzulassung bleibt nackt zulaessig - der Zuschnitt "
744
+ "ist nicht zu breit", _49_modellaufrufbar, M49_AUFRUF)
745
+
746
+ gegenprobe("49d", "Derselbe Name in einer anderen Spalte bleibt zulaessig - die Regel "
747
+ "gilt dem Ausloeser", _49_andere_spalte, M49_AUFRUF)
748
+
749
+ gegenprobe("49e", "Eine nackte Nennung bei Pruefmethode `review` bleibt zulaessig - "
750
+ "eine Durchsicht ruft keinen Skill auf", _49_andere_pruefmethode,
751
+ M49_AUFRUF)
752
+
753
+
754
+ # --- Gegenstand 2: der Ausloeser, der eine UEBUNG nennt (D-172) ----------------------
755
+ #
756
+ # FW-PO-02 nennt keinen Skill und erbt doch vier: Sein Ausloeser verweist auf UE3. Der
757
+ # Zuschnitt ist SCHMAL - gefragt wird, ob UEBERHAUPT ein ausdruecklicher Aufruf
758
+ # dasteht. Die beiden Gegenproben belegen genau das: eine fuer den bewussten Zuschnitt
759
+ # (FW-SC-01 nennt UE3 und ruft nur den dritten Schritt auf), eine fuer die Uebung ohne
760
+ # gesperrten Skill.
761
+ M49_UEBUNG = "und damit deren Ablauf"
762
+ M49_UEBUNGSANKER = "führt keinen Abschnitt der Form"
763
+ P49_UEBUNGSDATEI = ".koolie/core/onboarding/exercises/EXERCISES.md".replace("/", os.sep)
764
+
765
+
766
+ def _49_uebung_ohne_aufruf(root: str) -> None:
767
+ """Ein Ausloeser, der eine Uebung mit gesperrten Skills nennt und keinen Aufruf."""
768
+ _49_katalogzeile(root,
769
+ "| FW-SO-08 | Sondenzeile | Sondenvorbedingung | Ü3 aus "
770
+ "`.koolie/core/onboarding/exercises/EXERCISES.md` | Ablehnung | Zugriff "
771
+ "| sitzung | offen |")
772
+
773
+
774
+ def _49_uebung_mit_einem_aufruf(root: str) -> None:
775
+ """Dieselbe Uebung, aber ein Schritt ausdruecklich aufgerufen - der Fall FW-SC-01."""
776
+ _49_katalogzeile(root,
777
+ "| FW-SO-09 | Sondenzeile | Sondenvorbedingung | Ü3-Änderung, ausgelöst über "
778
+ "`/%s` | Ablehnung | Zugriff | sitzung | bestanden (Sondenbeleg, `.koolie/core/tests/protocols/2026-09-19-testblaetter-buendel-3.md`; Client Pack `claude-code` 2.1.278) |"
779
+ % _49_skill_ohne_modell(root))
780
+
781
+
782
+ def _49_uebung_ohne_gesperrten_skill(root: str) -> None:
783
+ """Eine Uebung, deren Abschnitt nur modellaufrufbare Skills fuehrt - UE1/UE2."""
784
+ _49_katalogzeile(root,
785
+ "| FW-SO-10 | Sondenzeile | Sondenvorbedingung | Ü1 aus "
786
+ "`.koolie/core/onboarding/exercises/EXERCISES.md` | Ablehnung | Zugriff "
787
+ "| sitzung | bestanden (Sondenbeleg, `.koolie/core/tests/protocols/2026-09-19-testblaetter-buendel-3.md`; Client Pack `claude-code` 2.1.278) |")
788
+
789
+
790
+ def _49_uebungsanker_verlieren(root: str) -> None:
791
+ """Ohne die Abschnittsueberschriften hat Gegenstand 2 keine Uebungen mehr."""
792
+ pfad = P(root, P49_UEBUNGSDATEI)
793
+ text = lies(pfad)
794
+ if "\n## Ü" not in text:
795
+ raise Praeparationsfehler(
796
+ "EXERCISES.md fuehrt keinen Abschnitt '## Ü<n>' - die Ankersonde zu 49 "
797
+ "haette nichts zu entfernen")
798
+ schreib(pfad, text.replace("\n## Ü", "\n## Uebung "))
799
+
800
+
801
+ sonde("49c", "Ein Ausloeser nennt eine Uebung mit vier gesperrten Skills und keinen "
802
+ "einzigen ausdruecklichen Aufruf - der Fall FW-PO-02",
803
+ _49_uebung_ohne_aufruf, M49_UEBUNG)
804
+
805
+ sonde("49d", "Ohne die Abschnittsueberschriften der Uebungsdatei meldet Gegenstand 2 "
806
+ "den verlorenen Anker, statt leise zu bestehen", _49_uebungsanker_verlieren,
807
+ M49_UEBUNGSANKER)
808
+
809
+ gegenprobe("49f", "Dieselbe Uebung mit EINEM ausdruecklichen Aufruf bleibt zulaessig - "
810
+ "der bewusste Zuschnitt von FW-SC-01", _49_uebung_mit_einem_aufruf,
811
+ M49_UEBUNG)
812
+
813
+ gegenprobe("49g", "Eine Uebung, deren Abschnitt keinen gesperrten Skill fuehrt, bleibt "
814
+ "ohne Aufruf zulaessig", _49_uebung_ohne_gesperrten_skill, M49_UEBUNG)
815
+
816
+
817
+ # --- Pruefung 50: Vollstaendigkeit des Klaerungspunktregisters (D-147) -------------
818
+ M50_FEHLT = "steht in keiner Registerzeile"
819
+ M50_ANKER = "hat ihren Anker verloren"
820
+ P50_LOG = ".koolie/core/governance/DECISION_LOG.md".replace("/", os.sep)
821
+ P50_ROADMAP = ".koolie/core/docs/ROADMAP.md".replace("/", os.sep)
822
+ # Eine Kennung, die es im Register nicht gibt und nie geben wird - die Sonde vergibt
823
+ # keine echte. 'Eine synthetische Kennung nimmt nie die naechste freie' (0.59.0).
824
+ #
825
+ # ZUSAMMENGESETZT, und das ist kein Trick, sondern der Gegenstand: Dieses Skript liegt
826
+ # im Kern, und Pruefung 50 meldet jede dort GENANNTE Kennung ohne Registerzeile. Stuende
827
+ # sie woertlich hier, muesste sie in die Ausnahmemenge - und dann meldete die Sonde
828
+ # nichts mehr. Eine Sonde, deren Gegenstand die eigene Nennung ist, darf sich nicht
829
+ # selbst nennen - auch nicht in dem Kommentar, der das erklaert. Der erste Entwurf
830
+ # dieses Absatzes tat es, und Pruefung 50 hat ihn gemeldet.
831
+ K50_SYNTH = "K-" + "95"
832
+
833
+
834
+ def _50_freie_kennung(root: str) -> str:
835
+ """Belegt, dass die Sondenkennung im Register wirklich fehlt - sonst misst sie nichts."""
836
+ if ("| " + K50_SYNTH + " |") in lies(P(root, P50_LOG)):
837
+ raise Praeparationsfehler(
838
+ "%s steht bereits im Register - die Sonde zu 50 braucht eine freie Kennung"
839
+ % K50_SYNTH)
840
+ return K50_SYNTH
841
+
842
+
843
+ def _50_nennung_ohne_register(root: str) -> None:
844
+ """Eine Kennung wird in einem Kerntraeger genannt und steht in keiner Registerzeile.
845
+
846
+ Genau der Fall von K-34 (sieben Traeger, seit 0.32.0) und K-55 (drei Traeger, als
847
+ 'neu' angekuendigt und nie eingetragen).
848
+ """
849
+ kennung = _50_freie_kennung(root)
850
+ pfad = P(root, P50_ROADMAP)
851
+ schreib(pfad, lies(pfad).rstrip("\r\n") + "\r\n\r\n"
852
+ + "Sondennachtrag: Offen bleibt die Frage nach dem Sondengegenstand (%s).\r\n"
853
+ % kennung)
854
+
855
+
856
+ def _50_anker_verlieren(root: str) -> None:
857
+ """Ohne den Absatz mit den synthetischen Kennungen hat Pruefung 50 keine Ausnahme mehr.
858
+
859
+ Sie leitet sie von dort ab; geht der Absatz verloren, meldete sie jede Sondenkennung
860
+ des Pruefapparats als Befund - oder, schlimmer, man naehme die Liste in den Code.
861
+ """
862
+ ersetze(P(root, P50_LOG),
863
+ ("**Belegte synthetische Kennungen", "**Frueher belegte Kennungen"))
864
+
865
+
866
+ def _50_nennung_mit_register(root: str) -> None:
867
+ """Dieselbe Nennung MIT Registerzeile bleibt zulaessig - das ist der erlaubte Fall."""
868
+ kennung = _50_freie_kennung(root)
869
+ _50_nennung_ohne_register(root)
870
+ zeile_nach(P(root, P50_LOG), "| K-56 | Ein dezentrales Testblatt",
871
+ "| %s | Sondenfrage? | niedrig | Sondenbegruendung | Sondenweg | offen |"
872
+ % kennung)
873
+
874
+
875
+ def _50_synthetische_kennung(root: str) -> None:
876
+ """Eine synthetische Kennung des Pruefapparats bleibt ohne Registerzeile zulaessig.
877
+
878
+ Ohne dieses Paar meldete die Pruefung ihre eigenen Sonden - der Zuschnitt waere zu
879
+ breit, und die Ausnahme haette keinen belegten Gegenstand.
880
+ """
881
+ pfad = P(root, P50_ROADMAP)
882
+ schreib(pfad, lies(pfad).rstrip("\r\n") + "\r\n\r\n"
883
+ + "Sondennachtrag: Die Gegenprobe benutzt die synthetische Kennung K-99.\r\n")
884
+
885
+
886
+ sonde("50a", "Eine Kennung, die ein Kerntraeger nennt und das Register nicht fuehrt, "
887
+ "wird gemeldet - der Fall von K-34 und K-55", _50_nennung_ohne_register,
888
+ M50_FEHLT)
889
+
890
+ sonde("50b", "Ohne den Absatz mit den synthetischen Kennungen meldet Pruefung 50 den "
891
+ "verlorenen Anker, statt leise zu bestehen", _50_anker_verlieren, M50_ANKER)
892
+
893
+ gegenprobe("50a", "Das unveraenderte Repositorium bleibt unbeanstandet - K-34 und K-55 "
894
+ "sind nachgetragen", None, M50_FEHLT)
895
+
896
+ gegenprobe("50b", "Dieselbe Nennung MIT Registerzeile bleibt zulaessig",
897
+ _50_nennung_mit_register, M50_FEHLT)
898
+
899
+ gegenprobe("50c", "Eine synthetische Kennung des Pruefapparats bleibt ohne Registerzeile "
900
+ "zulaessig - der Zuschnitt ist nicht zu breit", _50_synthetische_kennung,
901
+ M50_FEHLT)
902
+
903
+
904
+ # --- Pruefung 51: Ausfuellschlitz fuer einen festgelegten Overlay-Wert (D-150) -----
905
+ M51_SCHLITZ = "trägt einen Ausfüllschlitz, obwohl"
906
+ M51_ANKER = "Kontextquellentabelle mit dem Kopf"
907
+ P51_QUELLE = ".koolie/core/templates/project-overlay/OVERLAY.md".replace("/", os.sep)
908
+ P51_LAUFZEIT = (".koolie/core/framework/runtime/rules/20-project-overlay.md"
909
+ .replace("/", os.sep))
910
+ # Der Stand VOR 0.61.0, woertlich. Die Sonde stellt ihn wieder her: Sie misst genau den
911
+ # Befund, den dieses Release behoben hat, und nicht einen nachgebauten.
912
+ P51_ALTZEILE = '- Freigegebene externe Domains: `<TBD: Liste oder „keine">`'
913
+
914
+
915
+ def _zeile_ersetzen(pfad: str, praefix: str, neu: str) -> None:
916
+ """Die eine Zeile, die mit `praefix` beginnt, ganz ersetzen.
917
+
918
+ Fuer eine Praeparation, deren Gegenstand eine ganze Zeile ist, taugt kein Suchtext
919
+ ueber den Zeileninhalt: Er waere die Zeile selbst und muesste bei jeder Umformulierung
920
+ nachgezogen werden. Der Praefix ist der Feldname, und der ist der Gegenstand.
921
+ """
922
+ zeilen = lies(pfad).split("\r\n")
923
+ treffer = [i for i, z in enumerate(zeilen) if z.startswith(praefix)]
924
+ if len(treffer) != 1:
925
+ raise Praeparationsfehler(
926
+ "%s: Praefix %r steht %dx am Zeilenanfang, erwartet genau einmal"
927
+ % (os.path.basename(pfad), praefix, len(treffer)))
928
+ zeilen[treffer[0]] = neu
929
+ schreib(pfad, "\r\n".join(zeilen))
930
+
931
+
932
+ def _51_schlitz_zurueck(root: str) -> None:
933
+ """Der Stand vor 0.61.0: die Laufzeitfassung bietet an, was die Quelle ausschliesst."""
934
+ _zeile_ersetzen(P(root, P51_LAUFZEIT), "- Freigegebene externe Domains:", P51_ALTZEILE)
935
+
936
+
937
+ def _51_anker_verlieren(root: str) -> None:
938
+ """Ohne die Kontextquellentabelle hat Pruefung 51 keine Feldmenge mehr.
939
+
940
+ Sie leitet sie von dort ab; geht der Kopf verloren, pruefte sie nichts und bestuende
941
+ leise - genau die Bauform, die D-23 ausschliesst.
942
+ """
943
+ ersetze(P(root, P51_QUELLE),
944
+ ("| Kontextquelle | Kontextklasse | Freigabe | Bedingungen |",
945
+ "| Quelle | Klasse | Freigabe | Bedingungen |"))
946
+
947
+
948
+ def _51_quelle_oeffnet(root: str) -> None:
949
+ """Legt die QUELLE den Wert nicht fest, ist der Schlitz zulaessig - beides zusammen.
950
+
951
+ Das Paar belegt, dass die Pruefung die Quelle liest und nicht ein verdrahtetes Feld:
952
+ Derselbe Schlitz, der eben gemeldet wurde, bleibt unbeanstandet, sobald die Vorlage
953
+ ihn selbst offen laesst.
954
+ """
955
+ _51_schlitz_zurueck(root)
956
+ ersetze(P(root, P51_QUELLE),
957
+ ("| Freigegebene externe Domains (Fetch) | K0 | **„keine\"** |",
958
+ "| Freigegebene externe Domains (Fetch) | K0 | `<TBD: Liste oder "
959
+ "„keine\">` |"))
960
+
961
+
962
+ def _51_fremdes_feld(root: str) -> None:
963
+ """Ein Schlitz fuer ein Feld, das die Quellentabelle nicht fuehrt, bleibt zulaessig."""
964
+ zeile_nach(P(root, P51_LAUFZEIT), "- Freigegebene externe Domains:",
965
+ "- Freigegebene Sondenquellen: `<TBD: Liste oder „keine\">`")
966
+
967
+
968
+ sonde("51a", "Ein Ausfuellschlitz in der Laufzeitfassung fuer einen Wert, den die "
969
+ "Overlay-Vorlage festlegt, wird gemeldet", _51_schlitz_zurueck, M51_SCHLITZ)
970
+
971
+ sonde("51b", "Ohne den Kopf der Kontextquellentabelle meldet Pruefung 51 die verlorene "
972
+ "Feldmenge, statt leise zu bestehen", _51_anker_verlieren, M51_ANKER)
973
+
974
+ gegenprobe("51a", "Das unveraenderte Repositorium bleibt unbeanstandet - die Domainzeile "
975
+ "traegt seit 0.61.0 den festen Wert", None, M51_SCHLITZ)
976
+
977
+ gegenprobe("51b", "Laesst die Quelle den Wert selbst offen, bleibt derselbe Schlitz "
978
+ "zulaessig - die Pruefung liest die Vorlage", _51_quelle_oeffnet,
979
+ M51_SCHLITZ)
980
+
981
+ gegenprobe("51c", "Ein Schlitz fuer ein Feld ausserhalb der Quellentabelle bleibt "
982
+ "zulaessig - der Zuschnitt ist nicht zu breit", _51_fremdes_feld,
983
+ M51_SCHLITZ)
984
+
985
+
986
+ # --- Pruefung 52: V6-Gegenstand mit Freigabefolge (D-151) --------------------------
987
+ M52_FOLGE = "deren Rechtsfolge eine Freigabe ist"
988
+ M52_ANKER = "Delegationsverbotsliste ist nicht mehr auffindbar"
989
+ P52_LAUFZEIT = (".koolie/core/framework/runtime/rules/10-privacy-security.md"
990
+ .replace("/", os.sep))
991
+ P52_RISIKO = ".koolie/core/framework/core/09-risk-model.md".replace("/", os.sep)
992
+ P52_CL06 = ".koolie/core/checklists/06-security.md".replace("/", os.sep)
993
+ # Woertlich der Stand vor 0.61.0 - sechzig Releases lang stand er so.
994
+ P52_ALTSATZ = (
995
+ "Authentifizierung, Autorisierung, Sitzungsverwaltung, Kryptografie, "
996
+ "Security-Konfiguration, Eingabevalidierung an Systemgrenzen, Verarbeitung "
997
+ "personenbezogener Daten: Kontrollstufe hoch. Nur analysieren und planen; Umsetzung "
998
+ "ausschließlich nach dokumentierter Freigabe durch `<APPROVAL_ROLE>` und "
999
+ "`<SECURITY_CONTACT>`."
1000
+ )
1001
+
1002
+
1003
+ def _52_altsatz_zurueck(root: str) -> None:
1004
+ """Der Stand vor 0.61.0: ein Delegationsverbot in der Aufzaehlung mit Freigabefolge."""
1005
+ _zeile_ersetzen(P(root, P52_LAUFZEIT),
1006
+ "Stufe hoch: Authentifizierung, Autorisierung, Sitzungsverwaltung,",
1007
+ P52_ALTSATZ)
1008
+
1009
+
1010
+ def _52_anker_verlieren(root: str) -> None:
1011
+ """Ohne die V6-Zeile hat Pruefung 52 keine Begriffe mehr - sie leitet sie von dort ab."""
1012
+ ersetze(P(root, P52_RISIKO),
1013
+ ("| V6 | Änderungen an Produktionssystemen",
1014
+ "| V6-alt | Änderungen an Produktionssystemen"))
1015
+
1016
+
1017
+ def _52_nur_anwendungslogik(root: str) -> None:
1018
+ """Dieselbe Freigabefolge OHNE V6-Gegenstand bleibt zulaessig - das ist G-04."""
1019
+ zeile_nach(P(root, P52_CL06),
1020
+ "## Abbruch- und Eskalationskriterien",
1021
+ "\r\nSondennachtrag: Eine Änderung an Kryptografie oder "
1022
+ "Sitzungsverwaltung ist Kontrollstufe hoch; die Umsetzung erfolgt nach "
1023
+ "dokumentierter Freigabe durch `<APPROVAL_ROLE>`.")
1024
+
1025
+
1026
+ def _52_ohne_freigabefolge(root: str) -> None:
1027
+ """Ein V6-Gegenstand OHNE Freigabefolge bleibt zulaessig - die Regel gilt dem Paar."""
1028
+ zeile_nach(P(root, P52_CL06),
1029
+ "## Abbruch- und Eskalationskriterien",
1030
+ "\r\nSondennachtrag: Eine Sicherheitskonfiguration mit Schutzwirkung ist "
1031
+ "Kontrollstufe hoch und nicht delegierbar; zulässig sind Analyse und "
1032
+ "Planvorschlag.")
1033
+
1034
+
1035
+ def _52_langform_ausgenommen(root: str) -> None:
1036
+ """Die Langform, aus der die Begriffe stammen, darf beide Seiten in einem Absatz nennen.
1037
+
1038
+ Ohne diese Ausnahme meldete die Pruefung ausgerechnet den Text, der die Abgrenzung
1039
+ ZIEHT - und die Ausnahme ist abgeleitet: es ist die Datei, aus der gelesen wurde.
1040
+ """
1041
+ zeile_nach(P(root, P52_RISIKO),
1042
+ "## 5. Anwendungshinweise (Erläuterung)",
1043
+ "\r\nSondennachtrag zur Abgrenzung: Eine Sicherheitskonfiguration bleibt "
1044
+ "V6; eine Berechtigungsprüfung in der Anwendungslogik ist Kontrollstufe "
1045
+ "hoch, und ihre Umsetzung erfolgt nach dokumentierter Freigabe.")
1046
+
1047
+
1048
+ sonde("52a", "Ein Gegenstand von V6 in einer Aufzaehlung mit Freigabefolge wird gemeldet "
1049
+ "- der Stand vor 0.61.0", _52_altsatz_zurueck, M52_FOLGE)
1050
+
1051
+ sonde("52b", "Ohne die V6-Zeile der Delegationsverbotsliste meldet Pruefung 52 den "
1052
+ "verlorenen Gegenstand, statt leise zu bestehen", _52_anker_verlieren,
1053
+ M52_ANKER)
1054
+
1055
+ gegenprobe("52a", "Das unveraenderte Repositorium bleibt unbeanstandet - beide Fassungen "
1056
+ "trennen seit 0.61.0 Anwendungslogik vom Betrieb", None, M52_FOLGE)
1057
+
1058
+ gegenprobe("52b", "Dieselbe Freigabefolge ohne einen Gegenstand von V6 bleibt zulaessig - "
1059
+ "das ist der erlaubte Fall", _52_nur_anwendungslogik, M52_FOLGE)
1060
+
1061
+ gegenprobe("52c", "Ein Gegenstand von V6 ohne Freigabefolge bleibt zulaessig - die Regel "
1062
+ "gilt dem Paar, nicht dem Wort", _52_ohne_freigabefolge, M52_FOLGE)
1063
+
1064
+ gegenprobe("52d", "Die Langform, aus der die Begriffe stammen, bleibt ausgenommen - sie "
1065
+ "zieht die Abgrenzung und nennt beide Seiten", _52_langform_ausgenommen,
1066
+ M52_FOLGE)
1067
+
1068
+
1069
+ # --- Pruefung 53: Die Kriterium-2-Kette des Releaseplans (D-153) -------------------
1070
+ M53_KETTE = "Kette des Releaseplans reißt zwischen"
1071
+ M53_NULL = "Kette des Releaseplans endet bei"
1072
+ M53_ANKER = "liest den Releaseplan darunter"
1073
+ P53_ROADMAP = ".koolie/core/docs/ROADMAP.md".replace("/", os.sep)
1074
+ P53_UEBERSCHRIFT = "#### Der Releaseplan bis 1.0.0 und darüber hinaus"
1075
+ # Genau der Fehler, den 0.60.0 gemergt hat: Die Zelle wurde aus dem Posten genommen, seine
1076
+ # Zahl nachgezogen - und die des Folgepostens blieb stehen.
1077
+ P53_KETTE_SUCH = "Kriterium 2: **"
1078
+ P53_GLIED_RE = re.compile(r"Kriterium 2: \*\*(\d+) → (\d+)\*\*")
1079
+
1080
+
1081
+ # 🔴 DER ANKER IST ABGELEITET, NICHT GEPFLEGT - UND DAS ZUM DRITTEN MAL IN DREI
1082
+ # RELEASES. Bis 0.67.0 stand er hier als feste Zeichenkette ("**85 → 0**"), also auf
1083
+ # dem Inhalt EINES Postens. 0.63.0 hat dieselbe Bauform schon einmal an Gegenprobe 53b
1084
+ # behoben und den Fall im Kopfkommentar dort beschrieben - die beiden SONDEN blieben
1085
+ # gepflegt. Der Umbau des Releaseplans in 0.67.0 (ein Posten wird zu sieben) hat 53a
1086
+ # prompt fallen lassen: "Praeparation gebrochen".
1087
+ # Eine Abhilfe gilt fuer die Stelle, an der sie eingetragen wird, nicht fuer die
1088
+ # Bauform. Wer eine findet, sucht ihre Geschwister im selben Block.
1089
+ def _53_letztes_glied(root: str) -> str:
1090
+ """Die LETZTE Kettenzeile des Plans - sie schliesst die Kette und endet bei null."""
1091
+ text = lies(P(root, P53_ROADMAP))
1092
+ kette = [z for z in text.replace("\r\n", "\n").split("\n")
1093
+ if P53_KETTE_SUCH in z and P53_GLIED_RE.search(z)]
1094
+ if not kette:
1095
+ raise Praeparationsfehler(
1096
+ "ROADMAP.md: keine Zeile mit einer Kriterium-2-Kette gefunden - die Sonde "
1097
+ "zu 53 haette keinen Anker")
1098
+ return kette[-1]
1099
+
1100
+
1101
+ def _53_kette_reissen(root: str) -> None:
1102
+ """Der Stand vor 0.61.0: Der Folgeposten beginnt um eins unter dem Vorgaengerende."""
1103
+ glied = _53_letztes_glied(root)
1104
+ m = P53_GLIED_RE.search(glied)
1105
+ kaputt = P53_GLIED_RE.sub(
1106
+ "Kriterium 2: **%d → %s**" % (int(m.group(1)) - 1, m.group(2)), glied)
1107
+ ersetze(P(root, P53_ROADMAP), (glied, kaputt))
1108
+
1109
+
1110
+ def _53_null_verfehlen(root: str) -> None:
1111
+ """Ein Plan, der nicht bei null ankommt, fuehrt nicht bis 1.0.0."""
1112
+ glied = _53_letztes_glied(root)
1113
+ m = P53_GLIED_RE.search(glied)
1114
+ kaputt = P53_GLIED_RE.sub(
1115
+ "Kriterium 2: **%s → %d**" % (m.group(1), int(m.group(2)) + 1), glied)
1116
+ ersetze(P(root, P53_ROADMAP), (glied, kaputt))
1117
+
1118
+
1119
+ def _53_anker_verlieren(root: str) -> None:
1120
+ """Ohne die Ueberschrift liest Pruefung 53 keinen Plan - und sagt es."""
1121
+ ersetze(P(root, P53_ROADMAP),
1122
+ (P53_UEBERSCHRIFT, "#### Der Plan bis 1.0.0"))
1123
+
1124
+
1125
+ def _53_glied_anfuegen(root: str) -> None:
1126
+ """Ein weiterer Posten, der die Kette fortsetzt, bleibt zulaessig.
1127
+
1128
+ Die Pruefung rechnet eine Kette nach und zaehlt keine Posten; ohne dieses Paar waere
1129
+ nicht belegt, dass sie dem Plan folgt statt einer festen Laenge.
1130
+ """
1131
+ # DER ANKER IST ABGELEITET, NICHT GEPFLEGT - und das ist mit 0.63.0 noetig
1132
+ # geworden: Er stand zweimal in zwei Releases auf einer Postennummer, und beide
1133
+ # Male hat die Verschiebung des Releaseplans die Gegenprobe fallen lassen
1134
+ # ("Praeparation gebrochen"). Gesucht wird die LETZTE Zeile der Kette; dahinter
1135
+ # gehoert der Sondenposten, damit die Kette geschlossen bleibt.
1136
+ text = lies(P(root, P53_ROADMAP))
1137
+ kette = [z for z in text.replace("\r\n", "\n").split("\n")
1138
+ if P53_KETTE_SUCH in z]
1139
+ if not kette:
1140
+ raise Praeparationsfehler(
1141
+ "ROADMAP.md: keine Zeile mit einer Kriterium-2-Kette gefunden - die "
1142
+ "Gegenprobe haette keinen Anker")
1143
+ zeile_nach(P(root, P53_ROADMAP), kette[-1].strip(),
1144
+ "| **~0.99.0** | Sondenposten | Kriterium 2: **0 → 0** | nein |")
1145
+
1146
+
1147
+ def _53_nennung_vor_dem_plan(root: str) -> None:
1148
+ """Eine Kriterium-2-Angabe VOR der Ueberschrift bleibt zulaessig - der Zuschnitt beginnt dort."""
1149
+ ersetze(P(root, P53_ROADMAP),
1150
+ (P53_UEBERSCHRIFT,
1151
+ "Sondennachtrag: Eine Vorhersage ausserhalb des Plans, Kriterium 2: "
1152
+ "**99 → 1**.\r\n\r\n" + P53_UEBERSCHRIFT))
1153
+
1154
+
1155
+ sonde("53a", "Ein Folgeposten, der unter dem Ende seines Vorgaengers beginnt, wird "
1156
+ "gemeldet - genau der Fehler, den 0.60.0 gemergt hat", _53_kette_reissen,
1157
+ M53_KETTE)
1158
+
1159
+ sonde("53b", "Ein Plan, dessen Kette nicht bei null ankommt, wird gemeldet - Kriterium 2 "
1160
+ "muss dort ankommen", _53_null_verfehlen, M53_NULL)
1161
+
1162
+ sonde("53c", "Ohne die Ueberschrift des Releaseplans meldet Pruefung 53 den verlorenen "
1163
+ "Gegenstand, statt leise zu bestehen", _53_anker_verlieren, M53_ANKER)
1164
+
1165
+ gegenprobe("53a", "Das unveraenderte Repositorium bleibt unbeanstandet - die Kette "
1166
+ "schliesst und endet bei null", None, M53_KETTE)
1167
+
1168
+ gegenprobe("53b", "Ein weiterer Posten, der die Kette fortsetzt, bleibt zulaessig - "
1169
+ "gerechnet wird die Kette, nicht die Laenge", _53_glied_anfuegen,
1170
+ M53_KETTE)
1171
+
1172
+ gegenprobe("53c", "Eine Kriterium-2-Angabe vor der Ueberschrift bleibt zulaessig - der "
1173
+ "Zuschnitt beginnt am Plan", _53_nennung_vor_dem_plan, M53_KETTE)
1174
+
1175
+
1176
+ # --- Pruefung 54: Zusatzschluessel auf der deklarierten Ebene (D-155) --------------
1177
+ #
1178
+ # ZWEI ZUSCHNITTE, UND DER ZWEITE IST DER WICHTIGERE. Das Repositorium traegt eine
1179
+ # devin-desktop-Testinstallation, und dieses Pack fuehrt settings_extra ABSICHTLICH leer.
1180
+ # Eine Sonde auf der Kopie des Repositoriums belegt deshalb nur die Deklarationspflicht.
1181
+ # Was der Befund von 0.62.0 verlangt - dass ein Schluessel mit WERT auf der richtigen
1182
+ # EBENE ankommt -, ist nur an einer claude-code-Installation zu messen. Das ist B02: nicht,
1183
+ # dass eine Pruefung falsch prueft, sondern dass sie einen Client nicht sieht.
1184
+ M54_FEHLT_FELD = "Feld settings_extra fehlt"
1185
+ M54_FEHLT_KEY = "aus settings_extra fehlt in der obersten Ebene"
1186
+ M54_EBENE = "steht in dem Objekt permissions statt in der obersten Ebene"
1187
+ M54_WERT = "das Manifest deklariert in settings_extra aber"
1188
+ MAN_DD_54 = ".koolie/core/clients/devin-desktop/manifest.json".replace("/", os.sep)
1189
+
1190
+
1191
+ def _54_deklaration_fehlt(root: str) -> None:
1192
+ """Das Pack fuehrt das Feld gar nicht - der Stand jedes Packs bis 0.61.0."""
1193
+ ersetze(P(root, MAN_DD_54), (' "settings_extra": {},\r\n', ""))
1194
+
1195
+
1196
+ def _54_leeres_feld_bleibt(root: str) -> None:
1197
+ """Gegenprobe: Ein leeres settings_extra ist eine Deklaration und bleibt zulaessig.
1198
+
1199
+ Ohne dieses Paar stuende nur fest, dass die Pruefung ein fehlendes Feld meldet - nicht,
1200
+ dass sie die ausdrueckliche Abwesenheit von der Luecke unterscheidet. Genau diese
1201
+ Unterscheidung ist ihr Zweck.
1202
+ """
1203
+ ersetze(P(root, MAN_DD_54),
1204
+ (' "settings_extra": {},\r\n',
1205
+ ' "settings_extra": {},\r\n "_sonde_54": "leer ist eine Deklaration",\r\n'))
1206
+
1207
+
1208
+ def _cc_manifest_54(root: str) -> str:
1209
+ return os.path.join(root, ".koolie/core", "clients", "claude-code", "manifest.json")
1210
+
1211
+
1212
+ def sonden_zusatzschluessel() -> None:
1213
+ """Wirkungsnachweis an einer claude-code-Installation (D-155).
1214
+
1215
+ Gemessen wird an der ERZEUGTEN Datei, nicht am Manifest: Die Pruefung fragt, ob die
1216
+ Verschaerfung ankommt, und das entscheidet die Abbildung, nicht die Deklaration.
1217
+ """
1218
+ root = installation("claude-code")
1219
+ try:
1220
+ rechte = os.path.join(root, ".claude", "settings.json")
1221
+ ausgang = lies(rechte)
1222
+
1223
+ # --- Gegenprobe: die frische Installation traegt den Schluessel --------------
1224
+ # Sie ist hier die wichtigere Haelfte: Sie belegt, dass die Abbildung aus
1225
+ # 0.62.0 ueberhaupt etwas ausliefert. Ohne sie bewiese jede Sonde nur, dass die
1226
+ # Pruefung irgendetwas meldet.
1227
+ aus = validator_ausgabe(root)
1228
+ melde("GEGENPROBE", "54c", "autoMemoryEnabled" not in aus,
1229
+ "Die frische claude-code-Installation traegt autoMemoryEnabled auf der "
1230
+ "obersten Ebene und bleibt unbeanstandet")
1231
+ if "autoMemoryEnabled" in aus:
1232
+ notiz(" Ausgabe:", " | ".join(
1233
+ z for z in aus.splitlines() if "autoMemoryEnabled" in z)[:400])
1234
+
1235
+ # --- 54a: der Schluessel fehlt ganz - der Stand bis 0.61.0 ------------------
1236
+ # Die erzeugte Datei ist LF: install.py schreibt LF, git normalisiert. Ein
1237
+ # Suchtext mit \r\n traefe hier NICHT - anders als in den Manifest-Sonden, die
1238
+ # gegen das CRLF des Repositoriums laufen.
1239
+ schreib(rechte, ersetzt(
1240
+ ausgang,
1241
+ (' "autoMemoryEnabled": false,\n', ""),
1242
+ quelle=".claude/settings.json"))
1243
+ melde("SONDE", "54b", M54_FEHLT_KEY in validator_ausgabe(root),
1244
+ "Ein deklarierter Zusatzschluessel fehlt in der erzeugten Datei - die "
1245
+ "Verschaerfung kommt nicht an")
1246
+
1247
+ # --- 54b: der Schluessel steht auf der FALSCHEN Ebene -----------------------
1248
+ # Der eigentliche Gegenstand: Die Datei bleibt gueltiges JSON, der Schluessel ist
1249
+ # da, er wird nur nicht gelesen. Bis 0.61.0 haette nichts es gemeldet.
1250
+ schreib(rechte, ersetzt(
1251
+ ausgang,
1252
+ (' "autoMemoryEnabled": false,\n', ""),
1253
+ ('"permissions": {\n "defaultMode": "default",',
1254
+ '"permissions": {\n "autoMemoryEnabled": false,\n '
1255
+ '"defaultMode": "default",'),
1256
+ quelle=".claude/settings.json"))
1257
+ melde("SONDE", "54c", M54_EBENE in validator_ausgabe(root),
1258
+ "Derselbe Schluessel INNERHALB von permissions - gueltiges JSON, vom "
1259
+ "Client nicht gelesen, und die Pruefung nennt die Ebene")
1260
+
1261
+ # --- 54c: der Wert ist ein anderer als der deklarierte ----------------------
1262
+ schreib(rechte, ersetzt(
1263
+ ausgang,
1264
+ (' "autoMemoryEnabled": false,\n', ' "autoMemoryEnabled": true,\n'),
1265
+ quelle=".claude/settings.json"))
1266
+ melde("SONDE", "54d", M54_WERT in validator_ausgabe(root),
1267
+ "Der Schluessel steht auf der richtigen Ebene und traegt den "
1268
+ "entgegengesetzten Wert - eine Verschaerfung, die keine ist")
1269
+
1270
+ schreib(rechte, ausgang)
1271
+ finally:
1272
+ aufraeumen(os.path.dirname(root))
1273
+
1274
+
1275
+ sonde("54a", "Ein Pack fuehrt settings_extra gar nicht - der Stand jedes Packs bis "
1276
+ "0.61.0, und die Abwesenheit war nicht von der Luecke zu unterscheiden",
1277
+ _54_deklaration_fehlt, M54_FEHLT_FELD)
1278
+
1279
+ gegenprobe("54a", "Das unveraenderte Repositorium bleibt unbeanstandet - beide Packs "
1280
+ "fuehren beide Felder", None, M54_FEHLT_FELD)
1281
+
1282
+ gegenprobe("54b", "Ein LEERES settings_extra ist eine Deklaration und bleibt zulaessig - "
1283
+ "die Pruefung trennt die ausdrueckliche Abwesenheit von der Luecke",
1284
+ _54_leeres_feld_bleibt, M54_FEHLT_FELD)
1285
+
1286
+ buendel(sonden_zusatzschluessel,
1287
+ "Pruefung 54 an einer claude-code-Installation: fehlend, falsche Ebene und "
1288
+ "falscher Wert je eigens gemessen, dazu die unveraenderte Installation")
1289
+
1290
+
1291
+ # --- Pruefung 55 und 56: Pflichtplatzhalter und gesperrte Traeger (D-160, D-161) ---
1292
+ #
1293
+ # ZWEI ZUSCHNITTE, AUS EINEM GRUND: Teil (a) von Pruefung 55 liest die VORLAGE und laeuft
1294
+ # im gewoehnlichen Lauf. Teil (b) und Pruefung 56 lesen ein GEFUELLTES Overlay - und das
1295
+ # Repositorium traegt nur die unausgefuellte Vorlage, in der jeder Wert <TBD> ist.
1296
+ # Deshalb baut das Buendel eine frische Installation und schreibt genau die zwei
1297
+ # Bindungszeilen hinein, um die es geht. Alles andere an --strict-overlay meldet dort
1298
+ # ohnehin, und die Sonden pruefen je auf IHRE Meldung, nicht auf die Fehlerzahl.
1299
+ M55_VORLAGE = "kommt in der Vorlage aber nicht vor"
1300
+ M55_ANKER = "keine Zeile trägt 'Pflicht vor Aktivierung' = ja"
1301
+ M55_BINDUNG = "<ISSUE_TRACKER> wird von"
1302
+ M56_GESPERRT = "das dasselbe Overlay unter <EXCLUDED_PATHS> führt"
1303
+ P55_REG = ".koolie/core/docs/PLACEHOLDER_REGISTRY.md".replace("/", os.sep)
1304
+ P55_VOR = ".koolie/core/templates/project-overlay/OVERLAY.md".replace("/", os.sep)
1305
+
1306
+
1307
+ def _55_vorlage_luecke(root: str) -> None:
1308
+ """Ein Pflichtplatzhalter verschwindet aus der Vorlage - der Fall vom 2026-09-18."""
1309
+ ersetze(P(root, P55_VOR),
1310
+ ("| Änderungsschwelle (`CHANGE_SIZE_THRESHOLD`) |",
1311
+ "| Änderungsschwelle |"))
1312
+
1313
+
1314
+ def _55_anker_weg(root: str) -> None:
1315
+ """Ohne die Pflichtspalte hat Pruefung 55 keinen Gegenstand - und sagt es."""
1316
+ p = P(root, P55_REG)
1317
+ text = lies(p)
1318
+ # NICHT "| ja |": Eine der 29 Zeilen traegt 'ja (oder „keine")', bliebe stehen,
1319
+ # und die Pflichtmenge waere nicht leer - die Sonde maesse dann nichts.
1320
+ schreib(p, text.replace("| ja", "| spaeter"))
1321
+
1322
+
1323
+ def _55_ohne_overlayort(root: str) -> None:
1324
+ """Gegenprobe: Ein Pflichtplatzhalter, den das Register NICHT im Overlay verortet,
1325
+ muss in der Vorlage nicht vorkommen. `<FRAMEWORK_OWNER>` wird in OWNERS.md gesetzt -
1326
+ ohne diesen Zuschnitt meldete die Pruefung ihn bei jedem Lauf."""
1327
+ p = P(root, P55_VOR)
1328
+ text = lies(p)
1329
+ schreib(p, text.replace("<FRAMEWORK_OWNER>", "<FRAMEWORK-EIGNER>"))
1330
+
1331
+
1332
+ # 🔴 DIE SPITZEN KLAMMERN GEHOEREN HINEIN (K-88, D-257). Bis 0.83.0 schrieb dieser
1333
+ # Block `ISSUE_TRACKER` OHNE sie und nannte das eine Bindung - er kam damit durch, weil
1334
+ # Pruefung 55b `if name in text` fragte. **Die Gegenprobe deckte die Luecke der Pruefung,
1335
+ # und die Pruefung die der Gegenprobe.** Mit der geschaerften Pruefung faellt die alte
1336
+ # Form, und genau das ist ihr Wirkungsnachweis.
1337
+ BINDUNGEN = (
1338
+ "\n## Sondenabschnitt (nur fuer den Wirkungsnachweis)\n\n"
1339
+ "| Element | Platzhalter | Wert |\n|---|---|---|\n"
1340
+ "| Ticketsystem | `<ISSUE_TRACKER>` | Beispiel-Ticketsystem |\n"
1341
+ "| Merge-Request-Vorlage | `<MR_TEMPLATE_PATH>` | `%s` |\n"
1342
+ )
1343
+
1344
+ # Dieselbe Tabelle in der Form von 0.83.0: der Name OHNE Klammern. Sie ist der
1345
+ # Gegenstand der Sonde 55d - ein Overlay, das den Platzhalter nennt und nicht bindet.
1346
+ BINDUNGEN_NUR_GENANNT = BINDUNGEN.replace("`<ISSUE_TRACKER>`", "`ISSUE_TRACKER`")
1347
+
1348
+
1349
+ def _ov(root: str) -> str:
1350
+ return os.path.join(root, ".koolie/project-overlay", "OVERLAY.md")
1351
+
1352
+
1353
+ def sonden_platzhalterbindung() -> None:
1354
+ """Wirkungsnachweis fuer Pruefung 55b und 56 an einer gefuellten Installation."""
1355
+ root = installation("claude-code")
1356
+ try:
1357
+ pfad = _ov(root)
1358
+ ausgang = lies(pfad)
1359
+ # Eine ausgeschlossene Pfadmenge, die nicht <TBD> ist - sonst hat 56 keinen Anker.
1360
+ gefuellt = ersetzt(
1361
+ ausgang,
1362
+ ("`<TBD: z. B. deploy/**, infra/**, config/prod/**, **/fixtures/real/**>`",
1363
+ "`deploy/**`, `infra/**`"),
1364
+ quelle=".koolie/project-overlay/OVERLAY.md")
1365
+
1366
+ # --- Gegenprobe 55: der gebundene Platzhalter wird nicht beanstandet ---------
1367
+ schreib(pfad, gefuellt + BINDUNGEN % ".mr/pull_request_template.md")
1368
+ aus = strict_ausgabe(root)
1369
+ melde("GEGENPROBE", "55c", M55_BINDUNG not in aus,
1370
+ "Ein Overlay, das <ISSUE_TRACKER> BINDET, bleibt unbeanstandet - die "
1371
+ "Pruefung misst die Bindung, nicht das Vorhandensein eines Werts")
1372
+
1373
+ # --- Gegenprobe 56: derselbe Baum, Vorlage ausserhalb der Sperre -------------
1374
+ melde("GEGENPROBE", "56a", M56_GESPERRT not in aus,
1375
+ "Liegt der Wert von <MR_TEMPLATE_PATH> ausserhalb von <EXCLUDED_PATHS>, "
1376
+ "bleibt die Vorbedingung zulaessig")
1377
+
1378
+ # --- 55b: die Bindung fehlt, der Kerntext nennt den Platzhalter weiter -------
1379
+ # Der gemessene Fall ist die ERSETZUNG: Das Overlay nennt den Wert und den
1380
+ # Platzhalter nirgends mehr. In einer frischen Installation steht er noch in
1381
+ # der Prosa der Vorlage - die muss die Sonde mit entfernen, sonst gilt er als
1382
+ # gebunden und sie maesse nichts.
1383
+ ohne = gefuellt.replace("`<ISSUE_TRACKER>`", "Beispiel-Ticketsystem")
1384
+ schreib(pfad, ohne + (BINDUNGEN % ".mr/pull_request_template.md").replace(
1385
+ "| Ticketsystem | `<ISSUE_TRACKER>` | Beispiel-Ticketsystem |\n", ""))
1386
+ melde("SONDE", "55c", M55_BINDUNG in strict_ausgabe(root),
1387
+ "Das Overlay nennt den Wert, bindet den Platzhalter aber nicht - genau der "
1388
+ "Fall, der am 2026-09-18 fuenf Platzhalter in 65 Fundstellen unaufloesbar "
1389
+ "liess")
1390
+
1391
+ # --- 56: die Vorbedingung verlangt einen gesperrten Traeger ------------------
1392
+ schreib(pfad, gefuellt + BINDUNGEN % "deploy/pull_request_template.md")
1393
+ melde("SONDE", "56a", M56_GESPERRT in strict_ausgabe(root),
1394
+ "Eine Vorbedingung verlangt <MR_TEMPLATE_PATH>, und dessen Wert liegt "
1395
+ "unter einem ausgeschlossenen Pfad - die Zelle ist nicht fahrbar")
1396
+
1397
+ # --- Gegenprobe 56b: die NACHBARDATEI im selben Verzeichnis ---------------
1398
+ # Der erste Entwurf von Pruefung 56 verglich nur das erste Pfadsegment und
1399
+ # meldete `.github/pull_request_template.md` gegen `.github/workflows/**`.
1400
+ # Ohne dieses Paar stuende nur fest, dass die Pruefung einen gesperrten Pfad
1401
+ # findet - nicht, dass sie den ungesperrten Nachbarn in Ruhe laesst.
1402
+ nachbar = ersetzt(gefuellt, ("`deploy/**`, `infra/**`",
1403
+ "`deploy/gen/**`, `infra/**`"),
1404
+ quelle=".koolie/project-overlay/OVERLAY.md")
1405
+ schreib(pfad, nachbar + BINDUNGEN % "deploy/pull_request_template.md")
1406
+ melde("GEGENPROBE", "56b", M56_GESPERRT not in strict_ausgabe(root),
1407
+ "Derselbe Pfadanfang, ein anderer Pfad: `deploy/pull_request_template.md` gegen `deploy/gen/**` bleibt zulaessig - die Pruefung vergleicht Pfade, nicht Anfaenge")
1408
+
1409
+ # --- 55d: GENANNT ist nicht GEBUNDEN (K-88, D-257) --------------------------
1410
+ # 🔴 DER GEGENBEWEIS GEGEN DEN VORSTAND. Bis 0.83.0 fragte Pruefung 55b
1411
+ # `if name in text`; gegen diesen Baum haette sie GESCHWIEGEN, weil die
1412
+ # Buchstaben `ISSUE_TRACKER` im Overlay stehen - nur eben ohne die spitzen
1413
+ # Klammern, die den Kerntext aufloesen. Am Uebungsrepositorium waren es 14
1414
+ # von 26 Pflichtplatzhaltern, und die Pruefung meldete null.
1415
+ ohne_klammern = gefuellt.replace("`<ISSUE_TRACKER>`", "Beispiel-Ticketsystem")
1416
+ schreib(pfad, ohne_klammern
1417
+ + BINDUNGEN_NUR_GENANNT % ".mr/pull_request_template.md")
1418
+ melde("SONDE", "55d", M55_BINDUNG in strict_ausgabe(root),
1419
+ "Das Overlay NENNT <ISSUE_TRACKER> (ohne spitze Klammern) und bindet ihn "
1420
+ "nicht - bis 0.83.0 blieb genau das unbeanstandet (K-88, D-257)")
1421
+
1422
+ # --- Gegenprobe 55d: dieselbe Tabelle MIT Klammern --------------------------
1423
+ schreib(pfad, ohne_klammern + BINDUNGEN % ".mr/pull_request_template.md")
1424
+ melde("GEGENPROBE", "55d", M55_BINDUNG not in strict_ausgabe(root),
1425
+ "Dieselbe Tabelle mit spitzen Klammern bleibt unbeanstandet - die "
1426
+ "Pruefung misst die SCHREIBWEISE der Bindung und nicht den Wert daneben")
1427
+
1428
+ schreib(pfad, ausgang)
1429
+ finally:
1430
+ aufraeumen(os.path.dirname(root))
1431
+
1432
+
1433
+ sonde("55a", "Ein Pflichtplatzhalter fehlt in der Overlay-Vorlage - ein Projekt, das sie "
1434
+ "ausfuellt, begegnet ihm nie", _55_vorlage_luecke, M55_VORLAGE)
1435
+
1436
+ sonde("55b", "Ohne die Spalte 'Pflicht vor Aktivierung' meldet Pruefung 55 den "
1437
+ "verlorenen Gegenstand, statt leise zu bestehen", _55_anker_weg, M55_ANKER)
1438
+
1439
+ gegenprobe("55a", "Das unveraenderte Repositorium bleibt unbeanstandet - die Vorlage "
1440
+ "bietet jeden Pflichtplatzhalter an", None, M55_VORLAGE)
1441
+
1442
+ gegenprobe("55b", "Ein Pflichtplatzhalter, den das Register NICHT im Overlay verortet, "
1443
+ "muss in der Vorlage nicht stehen", _55_ohne_overlayort, M55_VORLAGE)
1444
+
1445
+ buendel(sonden_platzhalterbindung,
1446
+ "Pruefung 55b und 56 an einer gefuellten claude-code-Installation: fehlende "
1447
+ "Bindung und gesperrter Traeger je eigens gemessen, dazu beide Gegenproben")