@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.
- package/.gitattributes +16 -0
- package/.gitignore +51 -0
- package/.koolie/QUELLREPOSITORIUM.md +18 -0
- package/.koolie/core/CHANGELOG.md +11832 -0
- package/.koolie/core/LICENSE +674 -0
- package/.koolie/core/LICENSE-HINWEIS.md +98 -0
- package/.koolie/core/OWNERS.md +36 -0
- package/.koolie/core/VERSION +1 -0
- package/.koolie/core/banner.py +397 -0
- package/.koolie/core/build/README.md +34 -0
- package/.koolie/core/build/assemble.py +354 -0
- package/.koolie/core/build/build-docx.py +194 -0
- package/.koolie/core/build/doc/00-kopf.md +18 -0
- package/.koolie/core/build/doc/01-executive-summary.md +24 -0
- package/.koolie/core/build/doc/02-zielbild.md +13 -0
- package/.koolie/core/build/doc/03-ziele-nichtziele.md +28 -0
- package/.koolie/core/build/doc/04-geltungsbereich.md +25 -0
- package/.koolie/core/build/doc/05-glossar.md +47 -0
- package/.koolie/core/build/doc/06-leitprinzipien.md +5 -0
- package/.koolie/core/build/doc/07-architektur.md +60 -0
- package/.koolie/core/build/doc/07a-abbildungsschicht.md +66 -0
- package/.koolie/core/build/doc/08-trennung.md +24 -0
- package/.koolie/core/build/doc/09-betriebsmodi.md +18 -0
- package/.koolie/core/build/doc/10-arbeitsablauf.md +5 -0
- package/.koolie/core/build/doc/11-datenschutz.md +5 -0
- package/.koolie/core/build/doc/12-sicherheit.md +5 -0
- package/.koolie/core/build/doc/13-risiko.md +5 -0
- package/.koolie/core/build/doc/14-rollen.md +9 -0
- package/.koolie/core/build/doc/15-referenzstruktur.md +124 -0
- package/.koolie/core/build/doc/16-agentenanweisung.md +8 -0
- package/.koolie/core/build/doc/17-overlay.md +29 -0
- package/.koolie/core/build/doc/18-skill-standard.md +5 -0
- package/.koolie/core/build/doc/19-skill-template.md +5 -0
- package/.koolie/core/build/doc/20-referenz-skills.md +70 -0
- package/.koolie/core/build/doc/21-prompts.md +53 -0
- package/.koolie/core/build/doc/22-checklisten.md +49 -0
- package/.koolie/core/build/doc/23-entscheidungsbaeume.md +29 -0
- package/.koolie/core/build/doc/24-onboarding.md +33 -0
- package/.koolie/core/build/doc/25-governance.md +35 -0
- package/.koolie/core/build/doc/26-qs-test.md +9 -0
- package/.koolie/core/build/doc/27-pilot.md +13 -0
- package/.koolie/core/build/doc/28-uebernahme.md +5 -0
- package/.koolie/core/build/doc/29-grenzen.md +87 -0
- package/.koolie/core/build/doc/30-roadmap.md +5 -0
- package/.koolie/core/build/doc/31-anhaenge.md +151 -0
- package/.koolie/core/build/doc/32-abschluss.md +92 -0
- package/.koolie/core/build/ref-a4.docx +0 -0
- package/.koolie/core/checklists/01-preflight.md +54 -0
- package/.koolie/core/checklists/02-privacy-context.md +51 -0
- package/.koolie/core/checklists/03-before-code-change.md +51 -0
- package/.koolie/core/checklists/04-review-ai-code.md +58 -0
- package/.koolie/core/checklists/05-testing.md +48 -0
- package/.koolie/core/checklists/06-security.md +50 -0
- package/.koolie/core/checklists/07-new-dependency.md +57 -0
- package/.koolie/core/checklists/08-merge-request.md +47 -0
- package/.koolie/core/checklists/09-onboarding.md +52 -0
- package/.koolie/core/checklists/10-project-adoption.md +74 -0
- package/.koolie/core/checklists/11-framework-release.md +71 -0
- package/.koolie/core/checklists/README.md +28 -0
- package/.koolie/core/clientmap.py +1358 -0
- package/.koolie/core/clients/README.md +113 -0
- package/.koolie/core/clients/_template/CLIENT_PACK.md +197 -0
- package/.koolie/core/clients/claude-code/CLIENT_PACK.md +383 -0
- package/.koolie/core/clients/claude-code/manifest.json +232 -0
- package/.koolie/core/clients/claude-code/root-template/.claude/README.md +127 -0
- package/.koolie/core/clients/cursor/CLIENT_PACK.md +229 -0
- package/.koolie/core/clients/cursor/manifest.json +330 -0
- package/.koolie/core/clients/cursor/root-template/.cursor/README.md +36 -0
- package/.koolie/core/clients/devin-desktop/CLIENT_PACK.md +251 -0
- package/.koolie/core/clients/devin-desktop/manifest.json +163 -0
- package/.koolie/core/clients/devin-desktop/root-template/.devin/README.md +79 -0
- package/.koolie/core/clients/kiro/CLIENT_PACK.md +223 -0
- package/.koolie/core/clients/kiro/manifest.json +300 -0
- package/.koolie/core/clients/kiro/root-template/.kiro/README.md +37 -0
- package/.koolie/core/clients/openai-codex/CLIENT_PACK.md +257 -0
- package/.koolie/core/clients/openai-codex/manifest.json +208 -0
- package/.koolie/core/clients/openai-codex/root-template/.codex/README.md +35 -0
- package/.koolie/core/decision-trees/01-context-allowed.md +46 -0
- package/.koolie/core/decision-trees/02-may-ai-do-task.md +47 -0
- package/.koolie/core/decision-trees/03-analyze-or-modify.md +50 -0
- package/.koolie/core/decision-trees/04-required-review.md +49 -0
- package/.koolie/core/decision-trees/05-stop-or-escalate.md +47 -0
- package/.koolie/core/decision-trees/06-rule-placement.md +58 -0
- package/.koolie/core/decision-trees/README.md +14 -0
- package/.koolie/core/docs/ADOPTION_GUIDE.md +582 -0
- package/.koolie/core/docs/DOCUMENTATION_STANDARD.md +91 -0
- package/.koolie/core/docs/PLACEHOLDER_REGISTRY.md +79 -0
- package/.koolie/core/docs/ROADMAP.md +848 -0
- package/.koolie/core/docs/RUNTIME_GLOSSARY.md +113 -0
- package/.koolie/core/examples/README.md +11 -0
- package/.koolie/core/examples/example-ergebnisbericht.md +31 -0
- package/.koolie/core/examples/example-mr-description.md +31 -0
- package/.koolie/core/examples/example-overlay-runtime.md +48 -0
- package/.koolie/core/framework/core/00-principles.md +93 -0
- package/.koolie/core/framework/core/01-governance.md +58 -0
- package/.koolie/core/framework/core/02-privacy.md +141 -0
- package/.koolie/core/framework/core/03-security.md +86 -0
- package/.koolie/core/framework/core/04-quality.md +48 -0
- package/.koolie/core/framework/core/05-working-model.md +199 -0
- package/.koolie/core/framework/core/06-prompting-rules.md +51 -0
- package/.koolie/core/framework/core/07-review-rules.md +52 -0
- package/.koolie/core/framework/core/08-skill-conventions.md +115 -0
- package/.koolie/core/framework/core/09-risk-model.md +87 -0
- package/.koolie/core/framework/core/10-error-escalation.md +53 -0
- package/.koolie/core/framework/org-policies/MAPPING_CLASSIFICATION.md +16 -0
- package/.koolie/core/framework/org-policies/README.md +29 -0
- package/.koolie/core/framework/overlay-patterns/general/documents/branching-strategy/muster-general.md +43 -0
- package/.koolie/core/framework/overlay-patterns/general/documents/coding-guidelines/muster-general.md +82 -0
- package/.koolie/core/framework/overlay-patterns/general/documents/definition-of-done/muster-general.md +52 -0
- package/.koolie/core/framework/overlay-patterns/general/documents/definition-of-ready/muster-general.md +54 -0
- package/.koolie/core/framework/overlay-patterns/general/documents/quality/muster-general.md +59 -0
- package/.koolie/core/framework/overlay-patterns/general/documents/security/muster-general.md +52 -0
- package/.koolie/core/framework/overlay-patterns/general.md +150 -0
- package/.koolie/core/framework/role-packs/README.md +63 -0
- package/.koolie/core/framework/role-packs/_template/ROLE_PACK.md +58 -0
- package/.koolie/core/framework/role-packs/requirements-engineering/ROLE_PACK.md +158 -0
- package/.koolie/core/framework/role-packs/requirements-engineering/runtime/30-role-requirements-engineering.md +88 -0
- package/.koolie/core/framework/role-packs/requirements-engineering/skills/role-re-ticket/CHANGELOG.md +10 -0
- package/.koolie/core/framework/role-packs/requirements-engineering/skills/role-re-ticket/EXAMPLES.md +148 -0
- package/.koolie/core/framework/role-packs/requirements-engineering/skills/role-re-ticket/SKILL.md +195 -0
- package/.koolie/core/framework/role-packs/requirements-engineering/skills/role-re-ticket/TESTS.md +22 -0
- package/.koolie/core/framework/role-packs/software-development/ROLE_PACK.md +95 -0
- package/.koolie/core/framework/role-packs/software-development/runtime/30-role-software-development.md +26 -0
- package/.koolie/core/framework/runtime/agents/fw-reviewer.md +34 -0
- package/.koolie/core/framework/runtime/client-settings.json +3 -0
- package/.koolie/core/framework/runtime/hooks.json +20 -0
- package/.koolie/core/framework/runtime/mcp-config.example.json +4 -0
- package/.koolie/core/framework/runtime/permissions.json +106 -0
- package/.koolie/core/framework/runtime/root-instruction-local.example.md +19 -0
- package/.koolie/core/framework/runtime/root-instruction.md +116 -0
- package/.koolie/core/framework/runtime/rules/00-framework-core.md +49 -0
- package/.koolie/core/framework/runtime/rules/10-privacy-security.md +49 -0
- package/.koolie/core/framework/runtime/rules/15-development-rules.md +41 -0
- package/.koolie/core/framework/runtime/rules/16-plan-spezifikation.md +32 -0
- package/.koolie/core/framework/runtime/rules/20-project-overlay.md +60 -0
- package/.koolie/core/framework/skills/fw-bugfix-prepare/CHANGELOG.md +14 -0
- package/.koolie/core/framework/skills/fw-bugfix-prepare/EXAMPLES.md +57 -0
- package/.koolie/core/framework/skills/fw-bugfix-prepare/SKILL.md +177 -0
- package/.koolie/core/framework/skills/fw-bugfix-prepare/TESTS.md +15 -0
- package/.koolie/core/framework/skills/fw-change-analyze/CHANGELOG.md +12 -0
- package/.koolie/core/framework/skills/fw-change-analyze/EXAMPLES.md +66 -0
- package/.koolie/core/framework/skills/fw-change-analyze/SKILL.md +167 -0
- package/.koolie/core/framework/skills/fw-change-analyze/TESTS.md +16 -0
- package/.koolie/core/framework/skills/fw-change-small/CHANGELOG.md +13 -0
- package/.koolie/core/framework/skills/fw-change-small/EXAMPLES.md +68 -0
- package/.koolie/core/framework/skills/fw-change-small/SKILL.md +175 -0
- package/.koolie/core/framework/skills/fw-change-small/TESTS.md +13 -0
- package/.koolie/core/framework/skills/fw-code-explain/CHANGELOG.md +11 -0
- package/.koolie/core/framework/skills/fw-code-explain/EXAMPLES.md +61 -0
- package/.koolie/core/framework/skills/fw-code-explain/SKILL.md +163 -0
- package/.koolie/core/framework/skills/fw-code-explain/TESTS.md +11 -0
- package/.koolie/core/framework/skills/fw-docs-update/CHANGELOG.md +10 -0
- package/.koolie/core/framework/skills/fw-docs-update/EXAMPLES.md +59 -0
- package/.koolie/core/framework/skills/fw-docs-update/SKILL.md +160 -0
- package/.koolie/core/framework/skills/fw-docs-update/TESTS.md +12 -0
- package/.koolie/core/framework/skills/fw-error-analyze/CHANGELOG.md +10 -0
- package/.koolie/core/framework/skills/fw-error-analyze/EXAMPLES.md +67 -0
- package/.koolie/core/framework/skills/fw-error-analyze/SKILL.md +160 -0
- package/.koolie/core/framework/skills/fw-error-analyze/TESTS.md +12 -0
- package/.koolie/core/framework/skills/fw-mr-description/CHANGELOG.md +12 -0
- package/.koolie/core/framework/skills/fw-mr-description/EXAMPLES.md +69 -0
- package/.koolie/core/framework/skills/fw-mr-description/SKILL.md +170 -0
- package/.koolie/core/framework/skills/fw-mr-description/TESTS.md +12 -0
- package/.koolie/core/framework/skills/fw-overlay-pflege/CHANGELOG.md +7 -0
- package/.koolie/core/framework/skills/fw-overlay-pflege/EXAMPLES.md +48 -0
- package/.koolie/core/framework/skills/fw-overlay-pflege/SKILL.md +147 -0
- package/.koolie/core/framework/skills/fw-overlay-pflege/TESTS.md +13 -0
- package/.koolie/core/framework/skills/fw-plan/CHANGELOG.md +14 -0
- package/.koolie/core/framework/skills/fw-plan/EXAMPLES.md +69 -0
- package/.koolie/core/framework/skills/fw-plan/SKILL.md +168 -0
- package/.koolie/core/framework/skills/fw-plan/TESTS.md +14 -0
- package/.koolie/core/framework/skills/fw-refactor/CHANGELOG.md +10 -0
- package/.koolie/core/framework/skills/fw-refactor/EXAMPLES.md +70 -0
- package/.koolie/core/framework/skills/fw-refactor/SKILL.md +173 -0
- package/.koolie/core/framework/skills/fw-refactor/TESTS.md +14 -0
- package/.koolie/core/framework/skills/fw-repo-analyze/CHANGELOG.md +10 -0
- package/.koolie/core/framework/skills/fw-repo-analyze/EXAMPLES.md +52 -0
- package/.koolie/core/framework/skills/fw-repo-analyze/SKILL.md +149 -0
- package/.koolie/core/framework/skills/fw-repo-analyze/TESTS.md +11 -0
- package/.koolie/core/framework/skills/fw-review-support/CHANGELOG.md +12 -0
- package/.koolie/core/framework/skills/fw-review-support/EXAMPLES.md +69 -0
- package/.koolie/core/framework/skills/fw-review-support/SKILL.md +179 -0
- package/.koolie/core/framework/skills/fw-review-support/TESTS.md +13 -0
- package/.koolie/core/framework/skills/fw-tests/CHANGELOG.md +9 -0
- package/.koolie/core/framework/skills/fw-tests/EXAMPLES.md +65 -0
- package/.koolie/core/framework/skills/fw-tests/SKILL.md +169 -0
- package/.koolie/core/framework/skills/fw-tests/TESTS.md +12 -0
- package/.koolie/core/framework/tech-packs/README.md +15 -0
- package/.koolie/core/framework/tech-packs/_template/TECH_PACK.md +61 -0
- package/.koolie/core/governance/ADOPTION_REGISTRY.md +89 -0
- package/.koolie/core/governance/CHANGE_REQUEST_TEMPLATE.md +60 -0
- package/.koolie/core/governance/DECISION_LOG.md +779 -0
- package/.koolie/core/governance/EXCEPTION_PROCESS.md +31 -0
- package/.koolie/core/governance/FEEDBACK_PROCESS.md +34 -0
- package/.koolie/core/governance/FRAMEWORK_DEV_PROFILE.md +135 -0
- package/.koolie/core/governance/INCIDENT_HANDLING.md +47 -0
- package/.koolie/core/governance/PRIORITY_HIERARCHY.md +61 -0
- package/.koolie/core/governance/RACI.md +37 -0
- package/.koolie/core/governance/RELEASE_PROCESS.md +183 -0
- package/.koolie/core/governance/change-requests/CR-2026-001-definition-release-1-0-0.md +67 -0
- package/.koolie/core/governance/change-requests/CR-2026-002-client-packs.md +63 -0
- package/.koolie/core/governance/change-requests/CR-2026-003-install-client-schalter.md +70 -0
- package/.koolie/core/governance/change-requests/CR-2026-004-client-pack-claude-code.md +82 -0
- package/.koolie/core/governance/change-requests/CR-2026-005-kern-neutralisierung.md +75 -0
- package/.koolie/core/governance/change-requests/CR-2026-006-gemeinsame-skill-quelle.md +77 -0
- package/.koolie/core/governance/change-requests/CR-2026-007-geteilte-kernbestandteile.md +80 -0
- package/.koolie/core/governance/change-requests/CR-2026-008-berechtigungen-und-hooks.md +85 -0
- package/.koolie/core/governance/change-requests/CR-2026-009-umbenennung-leitwerk.md +77 -0
- package/.koolie/core/governance/change-requests/CR-2026-010-restduplikation.md +73 -0
- package/.koolie/core/governance/change-requests/CR-2026-011-hauptdokument.md +72 -0
- package/.koolie/core/governance/change-requests/CR-2026-012-schreibschutz-kernverzeichnis.md +106 -0
- package/.koolie/core/governance/change-requests/CR-2026-013-validator-blindstellen.md +128 -0
- package/.koolie/core/governance/change-requests/CR-2026-014-kurzform-langform.md +125 -0
- package/.koolie/core/governance/change-requests/CR-2026-015-versionskette.md +150 -0
- package/.koolie/core/governance/change-requests/CR-2026-016-ap2-claude-code.md +127 -0
- package/.koolie/core/governance/change-requests/CR-2026-017-ladebedingungen-claude-code.md +173 -0
- package/.koolie/core/governance/change-requests/CR-2026-018-quellenliste-claude-code.md +121 -0
- package/.koolie/core/governance/change-requests/CR-2026-019-strukturentscheidungen-fortschreiben.md +143 -0
- package/.koolie/core/governance/change-requests/CR-2026-020-akteursbezeichnung.md +118 -0
- package/.koolie/core/governance/change-requests/CR-2026-021-hook-interpreter.md +113 -0
- package/.koolie/core/governance/change-requests/CR-2026-022-artefaktversionen.md +73 -0
- package/.koolie/core/governance/change-requests/CR-2026-023-shell-lesesperre.md +128 -0
- package/.koolie/core/governance/change-requests/CR-2026-024-clientbindungen.md +78 -0
- package/.koolie/core/governance/change-requests/CR-2026-025-betriebsmodi.md +110 -0
- package/.koolie/core/governance/change-requests/CR-2026-026-fail-closed.md +134 -0
- package/.koolie/core/governance/change-requests/CR-2026-027-zeichenlimit-einstufung.md +105 -0
- package/.koolie/core/governance/change-requests/CR-2026-028-berechtigungsmodi.md +130 -0
- package/.koolie/core/governance/change-requests/CR-2026-029-hook-ablageort.md +115 -0
- package/.koolie/core/governance/change-requests/CR-2026-030-lesende-werkzeuge.md +143 -0
- package/.koolie/core/governance/change-requests/CR-2026-031-regelquellen-ausserhalb.md +182 -0
- package/.koolie/core/governance/change-requests/CR-2026-032-fremde-skill-ablage.md +151 -0
- package/.koolie/core/governance/change-requests/CR-2026-033-modusabhaengige-durchsetzung.md +131 -0
- package/.koolie/core/governance/change-requests/CR-2026-034-nachweisbedingungen.md +116 -0
- package/.koolie/core/governance/change-requests/CR-2026-035-readme-in-der-regelablage.md +115 -0
- package/.koolie/core/governance/change-requests/CR-2026-036-ortsangaben-hook-konfiguration.md +108 -0
- package/.koolie/core/governance/change-requests/CR-2026-037-meldender-hook-clientgebunden.md +133 -0
- package/.koolie/core/governance/change-requests/CR-2026-038-importsteuerung.md +159 -0
- package/.koolie/core/governance/change-requests/CR-2026-039-normative-saetze-in-kommentaren.md +124 -0
- package/.koolie/core/governance/change-requests/CR-2026-040-erh01-ist-clientgebunden.md +115 -0
- package/.koolie/core/governance/change-requests/CR-2026-041-s5-nicht-abbildbar.md +128 -0
- package/.koolie/core/governance/change-requests/CR-2026-042-abwesenheitsnachweis-suchwerkzeug.md +102 -0
- package/.koolie/core/governance/change-requests/CR-2026-043-validator-gibt-trefferwerte-aus.md +135 -0
- package/.koolie/core/governance/change-requests/CR-2026-044-aktivierungspruefung-clientgebunden.md +112 -0
- package/.koolie/core/governance/change-requests/CR-2026-045-update-verliert-die-clientwahl.md +116 -0
- package/.koolie/core/governance/change-requests/CR-2026-046-erstinstallation-ueberschreibt-projektdatei.md +125 -0
- package/.koolie/core/governance/change-requests/CR-2026-047-zusagen-je-zugriffskanal.md +133 -0
- package/.koolie/core/governance/change-requests/CR-2026-048-modusgrenze-ohne-durchsetzung.md +137 -0
- package/.koolie/core/governance/change-requests/CR-2026-049-sondenlauf-kodierungsabhaengig.md +126 -0
- package/.koolie/core/governance/change-requests/CR-2026-050-allowed-tools-und-verworfene-permissions.md +110 -0
- package/.koolie/core/governance/change-requests/CR-2026-051-quellenkarte-und-ueberholter-stand.md +110 -0
- package/.koolie/core/governance/change-requests/CR-2026-052-drei-regelkonflikte.md +166 -0
- package/.koolie/core/governance/change-requests/CR-2026-053-lesesperre-und-entwicklungsprofil.md +144 -0
- package/.koolie/core/governance/change-requests/CR-2026-054-aktivierung-verlangt-aktivitaet.md +124 -0
- package/.koolie/core/governance/change-requests/CR-2026-055-domain-ausnahme-ohne-mechanismus.md +173 -0
- package/.koolie/core/governance/change-requests/CR-2026-056-eingabeschema-und-pfadidentitaet.md +245 -0
- package/.koolie/core/governance/change-requests/CR-2026-057-disallowed-tools-und-s3.md +148 -0
- package/.koolie/core/governance/change-requests/CR-2026-058-unteragent-reichweite.md +203 -0
- package/.koolie/core/governance/change-requests/CR-2026-059-unteragent-tiefe-und-widerspruch.md +125 -0
- package/.koolie/core/governance/change-requests/CR-2026-060-stumme-brueche.md +170 -0
- package/.koolie/core/governance/change-requests/CR-2026-061-berechtigungsdatei-ohne-pruefung.md +169 -0
- package/.koolie/core/governance/change-requests/CR-2026-062-werkzeugabbildung-des-frontmatters.md +178 -0
- package/.koolie/core/governance/change-requests/CR-2026-063-skillaufruf-ohne-freigabe.md +207 -0
- package/.koolie/core/governance/change-requests/CR-2026-064-pruefregister-nicht-nachgezaehlt.md +141 -0
- package/.koolie/core/governance/change-requests/CR-2026-065-devin-suchwerkzeuge-erhoben.md +170 -0
- package/.koolie/core/governance/change-requests/CR-2026-066-schlitzdeckung-ohne-abgleich.md +153 -0
- package/.koolie/core/governance/change-requests/CR-2026-067-hookblock-und-praeparationsregister.md +140 -0
- package/.koolie/core/governance/change-requests/CR-2026-068-sondenlauf-nebenlaeufig.md +106 -0
- package/.koolie/core/governance/change-requests/CR-2026-069-bytecode-des-kerns.md +108 -0
- package/.koolie/core/governance/change-requests/CR-2026-070-d11-zaehler.md +114 -0
- package/.koolie/core/governance/change-requests/CR-2026-071-strukturentscheidungen-bestaetigen.md +322 -0
- package/.koolie/core/governance/change-requests/CR-2026-072-modulstatus-heben.md +315 -0
- package/.koolie/core/governance/change-requests/CR-2026-073-nicht-skill-traeger-heben.md +246 -0
- package/.koolie/core/governance/change-requests/CR-2026-074-restliche-nicht-skill-traeger-heben.md +271 -0
- package/.koolie/core/governance/change-requests/CR-2026-075-ap2-zielversion-devin-desktop.md +335 -0
- package/.koolie/core/governance/change-requests/CR-2026-076-erster-sitzungstest.md +455 -0
- package/.koolie/core/governance/change-requests/CR-2026-077-sitzungstest-schranken.md +425 -0
- package/.koolie/core/governance/change-requests/CR-2026-078-planung-nach-1-0-0.md +294 -0
- package/.koolie/core/governance/change-requests/CR-2026-079-umbenennung-vorziehen.md +233 -0
- package/.koolie/core/governance/change-requests/CR-2026-080-clientbindung-des-kerns.md +321 -0
- package/.koolie/core/governance/change-requests/CR-2026-081-produktnamen-im-kern.md +297 -0
- package/.koolie/core/governance/change-requests/CR-2026-082-sitzungstest-pi-ds-2.md +145 -0
- package/.koolie/core/governance/change-requests/CR-2026-083-sitzungstest-ne-sc.md +300 -0
- package/.koolie/core/governance/change-requests/CR-2026-084-trockenlauf-gegen-den-committeten-stand.md +117 -0
- package/.koolie/core/governance/change-requests/CR-2026-085-vorbedingungen-sitzungstest-5.md +182 -0
- package/.koolie/core/governance/change-requests/CR-2026-086-grenzfaelle-gegen-die-fassungen.md +164 -0
- package/.koolie/core/governance/change-requests/CR-2026-087-produktbeobachtung-quellenliste.md +206 -0
- package/.koolie/core/governance/change-requests/CR-2026-088-vorbedingungen-testblaetter.md +127 -0
- package/.koolie/core/governance/change-requests/CR-2026-089-herrichtung-uebungsrepositorium.md +226 -0
- package/.koolie/core/governance/change-requests/CR-2026-090-vorbedingungen-sitzungstest-5-zweiter-durchgang.md +255 -0
- package/.koolie/core/governance/change-requests/CR-2026-091-sitzungstest-5.md +163 -0
- package/.koolie/core/governance/change-requests/CR-2026-092-pruefmittelwort-und-buendelschnitt.md +226 -0
- package/.koolie/core/governance/change-requests/CR-2026-093-sechzehnte-praeparation.md +151 -0
- package/.koolie/core/governance/change-requests/CR-2026-094-testblaetter-buendel-1.md +113 -0
- package/.koolie/core/governance/change-requests/CR-2026-095-pruefapparat-filter.md +65 -0
- package/.koolie/core/governance/change-requests/CR-2026-096-vorbedingungen-buendel-2.md +225 -0
- package/.koolie/core/governance/change-requests/CR-2026-097-testblaetter-buendel-2.md +162 -0
- package/.koolie/core/governance/change-requests/CR-2026-098-anforderungen-auslieferung.md +93 -0
- package/.koolie/core/governance/change-requests/CR-2026-099-k74-und-vorbedingungen-buendel-3.md +119 -0
- package/.koolie/core/governance/change-requests/CR-2026-100-testblaetter-buendel-3.md +120 -0
- package/.koolie/core/governance/change-requests/CR-2026-101-k77-eigener-posten.md +165 -0
- package/.koolie/core/governance/change-requests/CR-2026-102-k77-entschieden.md +118 -0
- package/.koolie/core/governance/change-requests/CR-2026-103-vorbedingungen-buendel-4.md +76 -0
- package/.koolie/core/governance/change-requests/CR-2026-104-herrichtung-buendel-4.md +82 -0
- package/.koolie/core/governance/change-requests/CR-2026-105-messapparat-buendel-4.md +227 -0
- package/.koolie/core/governance/change-requests/CR-2026-106-uebergabe-einchecken.md +91 -0
- package/.koolie/core/governance/change-requests/CR-2026-107-uebergabe-im-release-commit.md +111 -0
- package/.koolie/core/governance/change-requests/CR-2026-108-testblaetter-buendel-4.md +118 -0
- package/.koolie/core/governance/change-requests/CR-2026-109-berichtsweg-des-aufraeumers.md +108 -0
- package/.koolie/core/governance/change-requests/CR-2026-110-vorbedingungen-des-nachlaufs.md +184 -0
- package/.koolie/core/governance/change-requests/CR-2026-111-der-apparat-auf-dem-weg-der-wiederaufnahme.md +127 -0
- package/.koolie/core/governance/change-requests/CR-2026-112-der-arbeitsplatz-im-kern.md +103 -0
- package/.koolie/core/governance/change-requests/CR-2026-113-nachlauf-buendel-4.md +103 -0
- package/.koolie/core/governance/change-requests/CR-2026-114-vorbedingungen-buendel-5.md +317 -0
- package/.koolie/core/governance/change-requests/CR-2026-115-herrichtung-buendel-5.md +244 -0
- package/.koolie/core/governance/change-requests/CR-2026-116-messtag-buendel-5.md +178 -0
- package/.koolie/core/governance/change-requests/CR-2026-117-sammelzellen-zentraler-katalog.md +251 -0
- package/.koolie/core/governance/change-requests/CR-2026-118-quellenzuordnung-matrixzeilen.md +115 -0
- package/.koolie/core/governance/change-requests/CR-2026-119-umbenennung-koolie.md +204 -0
- package/.koolie/core/governance/change-requests/CR-2026-120-ap2-rest-devin-desktop.md +96 -0
- package/.koolie/core/governance/change-requests/CR-2026-121-verify-marker-abschaffen.md +185 -0
- package/.koolie/core/governance/change-requests/CR-2026-122-umbenennung-koolie-lauf.md +131 -0
- package/.koolie/core/governance/change-requests/CR-2026-123-vortrag-und-namensabsatz.md +170 -0
- package/.koolie/core/governance/change-requests/CR-2026-124-hauptdokument-ap11.md +237 -0
- package/.koolie/core/governance/change-requests/CR-2026-125-word-fassung-und-blinder-fleck.md +204 -0
- package/.koolie/core/governance/change-requests/CR-2026-126-lizenz-gpl3.md +112 -0
- package/.koolie/core/governance/change-requests/CR-2026-127-gegenzeichnung-rollenfrage.md +96 -0
- package/.koolie/core/governance/change-requests/CR-2026-128-freigabelauf-1.0.0.md +278 -0
- package/.koolie/core/governance/change-requests/CR-2026-129-archiv-zeilenenden.md +90 -0
- package/.koolie/core/governance/change-requests/CR-2026-130-reihenfolge-des-hebens.md +204 -0
- package/.koolie/core/governance/change-requests/CR-2026-131-chronik-und-vorlage.md +194 -0
- package/.koolie/core/governance/change-requests/CR-2026-132-erhebung-openai-codex.md +185 -0
- package/.koolie/core/governance/change-requests/CR-2026-133-bau-openai-codex.md +97 -0
- package/.koolie/core/governance/change-requests/CR-2026-134-uebergabe-lokal.md +117 -0
- package/.koolie/core/governance/change-requests/CR-2026-135-pfadlisten-nul-getrennt.md +139 -0
- package/.koolie/core/governance/change-requests/CR-2026-136-overlay-werte-einordnung.md +156 -0
- package/.koolie/core/governance/change-requests/CR-2026-137-kopierweg-kern.md +144 -0
- package/.koolie/core/governance/change-requests/CR-2026-138-overlay-muster-general.md +118 -0
- package/.koolie/core/governance/change-requests/CR-2026-139-overlay-muster-dokumente.md +105 -0
- package/.koolie/core/governance/change-requests/CR-2026-140-installer-je-zielsystem.md +120 -0
- package/.koolie/core/governance/change-requests/CR-2026-141-lieferumfang.md +123 -0
- package/.koolie/core/governance/change-requests/CR-2026-142-dokumentationsstandard.md +90 -0
- package/.koolie/core/governance/change-requests/CR-2026-143-klasse-b-core-laufzeit.md +89 -0
- package/.koolie/core/governance/change-requests/CR-2026-144-klasse-b-governance.md +90 -0
- package/.koolie/core/governance/change-requests/CR-2026-145-klasse-b-skills.md +81 -0
- package/.koolie/core/governance/change-requests/CR-2026-146-code-pack-posten.md +84 -0
- package/.koolie/core/governance/change-requests/CR-2026-147-regel-register-posten.md +78 -0
- package/.koolie/core/governance/change-requests/CR-2026-148-mehrprojekt-tokenlast.md +70 -0
- package/.koolie/core/governance/change-requests/CR-2026-149-regelablage-pfadtoken.md +71 -0
- package/.koolie/core/governance/change-requests/CR-2026-150-client-pack-kiro.md +76 -0
- package/.koolie/core/governance/change-requests/CR-2026-151-skill-anweisungen.md +71 -0
- package/.koolie/core/governance/change-requests/CR-2026-152-testblaetter-modellwechsel.md +78 -0
- package/.koolie/core/governance/change-requests/CR-2026-153-attributionszeile.md +88 -0
- package/.koolie/core/governance/change-requests/CR-2026-154-auffindbarkeit.md +102 -0
- package/.koolie/core/governance/change-requests/CR-2026-155-client-pack-cursor.md +80 -0
- package/.koolie/core/governance/change-requests/CR-2026-156-mandat-und-reibung.md +100 -0
- package/.koolie/core/governance/change-requests/CR-2026-157-mcp-anbindung.md +93 -0
- package/.koolie/core/governance/change-requests/CR-2026-158-registerpflege.md +69 -0
- package/.koolie/core/governance/change-requests/CR-2026-159-powershell.md +49 -0
- package/.koolie/core/governance/change-requests/CR-2026-160-messapparat.md +59 -0
- package/.koolie/core/governance/change-requests/CR-2026-161-pruefwerkzeuge.md +52 -0
- package/.koolie/core/governance/change-requests/CR-2026-162-schutzschicht.md +65 -0
- package/.koolie/core/governance/change-requests/CR-2026-163-pfadsemantik.md +61 -0
- package/.koolie/core/governance/change-requests/CR-2026-164-modi-ausnahmen.md +65 -0
- package/.koolie/core/governance/change-requests/CR-2026-165-installer-banner.md +406 -0
- package/.koolie/core/governance/change-requests/CR-2026-166-nachlauf-aufzeichnungen.md +59 -0
- package/.koolie/core/governance/change-requests/CR-2026-167-einsatzarchitektur.md +60 -0
- package/.koolie/core/governance/change-requests/CR-2026-168-paketquellen.md +64 -0
- package/.koolie/core/governance/change-requests/CR-2026-169-modusbindung-messfragen.md +58 -0
- package/.koolie/core/governance/change-requests/CR-2026-170-erste-veroeffentlichung.md +62 -0
- package/.koolie/core/governance/change-requests/CR-2026-171-befehl-im-projektverzeichnis.md +57 -0
- package/.koolie/core/governance/change-requests/CR-2026-172-auftritt-npm-suche.md +58 -0
- package/.koolie/core/install.py +2402 -0
- package/.koolie/core/install_dialog.py +227 -0
- package/.koolie/core/koexistenz.py +112 -0
- package/.koolie/core/mandat.py +605 -0
- package/.koolie/core/onboarding/COMPLETION_CRITERIA.md +37 -0
- package/.koolie/core/onboarding/GUIDE.md +103 -0
- package/.koolie/core/onboarding/KNOWLEDGE_CHECK.md +48 -0
- package/.koolie/core/onboarding/MENTOR_CHECKLIST.md +40 -0
- package/.koolie/core/onboarding/QUICKSTART.md +50 -0
- package/.koolie/core/onboarding/REFERENCE.md +69 -0
- package/.koolie/core/onboarding/exercises/EXERCISES.md +78 -0
- package/.koolie/core/onboarding/exercises/README.md +120 -0
- package/.koolie/core/pilot/METRICS.md +59 -0
- package/.koolie/core/pilot/PILOT_CONCEPT.md +42 -0
- package/.koolie/core/prompts/01-understand-codebase.md +99 -0
- package/.koolie/core/prompts/02-impact-analysis.md +104 -0
- package/.koolie/core/prompts/03-implementation-planning.md +102 -0
- package/.koolie/core/prompts/04-code-generation.md +100 -0
- package/.koolie/core/prompts/05-test-generation.md +103 -0
- package/.koolie/core/prompts/06-refactoring.md +102 -0
- package/.koolie/core/prompts/07-debugging.md +97 -0
- package/.koolie/core/prompts/08-security-review.md +92 -0
- package/.koolie/core/prompts/09-performance-analysis.md +89 -0
- package/.koolie/core/prompts/10-documentation.md +91 -0
- package/.koolie/core/prompts/11-merge-request-review.md +94 -0
- package/.koolie/core/prompts/12-developer-training.md +90 -0
- package/.koolie/core/prompts/README.md +88 -0
- package/.koolie/core/templates/MR_AI_DISCLOSURE.md +37 -0
- package/.koolie/core/templates/PLAN_TEMPLATE.md +57 -0
- package/.koolie/core/templates/SKILL_TEMPLATE.md +159 -0
- package/.koolie/core/templates/project-overlay/OVERLAY.md +315 -0
- package/.koolie/core/templates/project-overlay/documents/README.md +43 -0
- package/.koolie/core/templates/project-overlay/documents/ai-governance/.gitkeep.md +3 -0
- package/.koolie/core/templates/project-overlay/documents/ai-process-model/.gitkeep.md +3 -0
- package/.koolie/core/templates/project-overlay/documents/architecture/.gitkeep.md +3 -0
- package/.koolie/core/templates/project-overlay/documents/architecture/decisions/README.md +3 -0
- package/.koolie/core/templates/project-overlay/documents/branching-strategy/.gitkeep.md +3 -0
- package/.koolie/core/templates/project-overlay/documents/coding-guidelines/.gitkeep.md +3 -0
- package/.koolie/core/templates/project-overlay/documents/definition-of-done/.gitkeep.md +3 -0
- package/.koolie/core/templates/project-overlay/documents/definition-of-ready/.gitkeep.md +3 -0
- package/.koolie/core/templates/project-overlay/documents/deployment/.gitkeep.md +3 -0
- package/.koolie/core/templates/project-overlay/documents/glossary/.gitkeep.md +3 -0
- package/.koolie/core/templates/project-overlay/documents/quality/.gitkeep.md +3 -0
- package/.koolie/core/templates/project-overlay/documents/roadmap/.gitkeep.md +3 -0
- package/.koolie/core/templates/project-overlay/documents/roles/.gitkeep.md +3 -0
- package/.koolie/core/templates/project-overlay/documents/security/.gitkeep.md +3 -0
- package/.koolie/core/templates/project-overlay/exceptions/EXCEPTIONS.md +9 -0
- package/.koolie/core/templates/project-overlay/forbidden-terms.txt +8 -0
- package/.koolie/core/templates/project-overlay/overlay-manifest.yaml +73 -0
- package/.koolie/core/templates/rules/21-overlay-TEMPLATE.md.template +28 -0
- package/.koolie/core/templates/rules/40-tech-TEMPLATE.md.template +33 -0
- package/.koolie/core/tests/EDGE_CASES.md +67 -0
- package/.koolie/core/tests/TEST_CATALOG.md +170 -0
- package/.koolie/core/tests/erhebungen/README.md +326 -0
- package/.koolie/core/tests/erhebungen/ablage.py +357 -0
- package/.koolie/core/tests/erhebungen/apparat/__init__.py +22 -0
- package/.koolie/core/tests/erhebungen/apparat/baum.py +214 -0
- package/.koolie/core/tests/erhebungen/apparat/belege.py +91 -0
- package/.koolie/core/tests/erhebungen/apparat/clients.py +321 -0
- package/.koolie/core/tests/erhebungen/apparat/freigabe.py +74 -0
- package/.koolie/core/tests/erhebungen/apparat/kontingent.py +64 -0
- package/.koolie/core/tests/erhebungen/apparat/laeufer.py +155 -0
- package/.koolie/core/tests/erhebungen/apparat/reihe.py +202 -0
- package/.koolie/core/tests/erhebungen/apparat/selbsttest.py +280 -0
- package/.koolie/core/tests/erhebungen/apparat/stand.py +30 -0
- package/.koolie/core/tests/erhebungen/apparat/vorpruefung.py +70 -0
- package/.koolie/core/tests/erhebungen/auswerten-b4.py +468 -0
- package/.koolie/core/tests/erhebungen/auswerten-b5.py +517 -0
- package/.koolie/core/tests/erhebungen/auswerten-dd.py +172 -0
- package/.koolie/core/tests/erhebungen/baeume-b4.py +334 -0
- package/.koolie/core/tests/erhebungen/baeume-b5.py +339 -0
- package/.koolie/core/tests/erhebungen/baeume_loeschen.py +138 -0
- package/.koolie/core/tests/erhebungen/cc-overlay-fuellen.py +277 -0
- package/.koolie/core/tests/erhebungen/dossier-b4.py +178 -0
- package/.koolie/core/tests/erhebungen/dossier-b5.py +202 -0
- package/.koolie/core/tests/erhebungen/historie-bauen-b4.py +642 -0
- package/.koolie/core/tests/erhebungen/k-bauen-b3.py +841 -0
- package/.koolie/core/tests/erhebungen/lauf-dd.py +146 -0
- package/.koolie/core/tests/erhebungen/lauf.py +114 -0
- package/.koolie/core/tests/erhebungen/mcp-waechter.py +278 -0
- package/.koolie/core/tests/erhebungen/messbaum-schnitt.py +256 -0
- package/.koolie/core/tests/erhebungen/messen.py +72 -0
- package/.koolie/core/tests/erhebungen/node-waechter.py +74 -0
- package/.koolie/core/tests/erhebungen/packaktivierung.py +403 -0
- package/.koolie/core/tests/erhebungen/prompts-schreiben-b4.py +210 -0
- package/.koolie/core/tests/erhebungen/prompts-schreiben-b5.py +251 -0
- package/.koolie/core/tests/erhebungen/reihe-b4.py +171 -0
- package/.koolie/core/tests/erhebungen/reihe-b5.py +172 -0
- package/.koolie/core/tests/erhebungen/stand-b4.py +135 -0
- package/.koolie/core/tests/erhebungen/stand-b5.py +137 -0
- package/.koolie/core/tests/erhebungen/trust-b4.py +56 -0
- package/.koolie/core/tests/erhebungen/trust-b5.py +56 -0
- package/.koolie/core/tests/erhebungen/turn2-schreiben-b4.py +105 -0
- package/.koolie/core/tests/erhebungen/umgebungen-bauen-b4.py +377 -0
- package/.koolie/core/tests/erhebungen/umgebungen-bauen-b5.py +363 -0
- package/.koolie/core/tests/erhebungen/zaehlen46.py +74 -0
- package/.koolie/core/tests/erhebungen/zustand-b4.py +82 -0
- package/.koolie/core/tests/erhebungen/zustand-b5.py +82 -0
- package/.koolie/core/tests/protocols/2026-09-10-AP2-claude-code-wirkungsnachweise.md +194 -0
- package/.koolie/core/tests/protocols/2026-09-10-AP2-claude-code.md +468 -0
- package/.koolie/core/tests/protocols/2026-09-10-CR-2026-020-akteursbezeichnung.md +99 -0
- package/.koolie/core/tests/protocols/2026-09-10-CR-2026-021-hook-interpreter.md +138 -0
- package/.koolie/core/tests/protocols/2026-09-10-CR-2026-022-artefaktversionen.md +87 -0
- package/.koolie/core/tests/protocols/2026-09-10-CR-2026-023-shell-lesesperre.md +135 -0
- package/.koolie/core/tests/protocols/2026-09-10-CR-2026-024-clientbindungen.md +98 -0
- package/.koolie/core/tests/protocols/2026-09-10-FW-DS-03.md +90 -0
- package/.koolie/core/tests/protocols/2026-09-10-FW-KO-01.md +105 -0
- package/.koolie/core/tests/protocols/2026-09-10-FW-KO-02.md +123 -0
- package/.koolie/core/tests/protocols/2026-09-10-FW-KO-04.md +73 -0
- package/.koolie/core/tests/protocols/2026-09-10-FW-RE-02.md +99 -0
- package/.koolie/core/tests/protocols/2026-09-10-FW-VN-01-wiederholung.md +108 -0
- package/.koolie/core/tests/protocols/2026-09-10-FW-VN-01.md +249 -0
- package/.koolie/core/tests/protocols/2026-09-10-FW-ZA-05.md +99 -0
- package/.koolie/core/tests/protocols/2026-09-11-AP2-devin-desktop.md +257 -0
- package/.koolie/core/tests/protocols/2026-09-11-CR-2026-026-fail-closed.md +113 -0
- package/.koolie/core/tests/protocols/2026-09-11-erhebungen-K21-K26.md +243 -0
- package/.koolie/core/tests/protocols/2026-09-11-wirkungsnachweise-0.26.0.md +101 -0
- package/.koolie/core/tests/protocols/2026-09-12-B01-allowed-tools.md +152 -0
- package/.koolie/core/tests/protocols/2026-09-12-B04-B05-gegenpruefung.md +204 -0
- package/.koolie/core/tests/protocols/2026-09-12-erhebungen-K28-S5-B9-bypass.md +268 -0
- package/.koolie/core/tests/protocols/2026-09-12-mehrprojekt-arbeitsbereich.md +154 -0
- package/.koolie/core/tests/protocols/2026-09-12-wirkungsnachweise-0.26.1.md +126 -0
- package/.koolie/core/tests/protocols/2026-09-12-wirkungsnachweise-0.27.0.md +114 -0
- package/.koolie/core/tests/protocols/2026-09-12-wirkungsnachweise-0.28.0.md +129 -0
- package/.koolie/core/tests/protocols/2026-09-12-wirkungsnachweise-0.29.0.md +121 -0
- package/.koolie/core/tests/protocols/2026-09-12-wirkungsnachweise-0.30.0.md +112 -0
- package/.koolie/core/tests/protocols/2026-09-12-wirkungsnachweise-0.31.0.md +107 -0
- package/.koolie/core/tests/protocols/2026-09-13-B06-gegenpruefung.md +370 -0
- package/.koolie/core/tests/protocols/2026-09-13-B07-B09-gegenpruefung.md +211 -0
- package/.koolie/core/tests/protocols/2026-09-13-B08-B11-gegenpruefung.md +179 -0
- package/.koolie/core/tests/protocols/2026-09-13-erhebung-disallowed-tools.md +147 -0
- package/.koolie/core/tests/protocols/2026-09-13-erhebung-unteragent-tiefe.md +139 -0
- package/.koolie/core/tests/protocols/2026-09-13-erhebung-unteragent.md +214 -0
- package/.koolie/core/tests/protocols/2026-09-13-gegenpruefung-berechtigungsdatei.md +253 -0
- package/.koolie/core/tests/protocols/2026-09-13-gegenpruefung-stumme-brueche.md +202 -0
- package/.koolie/core/tests/protocols/2026-09-13-gegenpruefung-werkzeugabbildung.md +219 -0
- package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.32.0.md +133 -0
- package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.33.0.md +169 -0
- package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.34.0.md +187 -0
- package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.35.0.md +187 -0
- package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.36.0.md +137 -0
- package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.37.0.md +112 -0
- package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.38.0.md +154 -0
- package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.39.0.md +188 -0
- package/.koolie/core/tests/protocols/2026-09-13-wirkungsnachweise-0.40.0.md +214 -0
- package/.koolie/core/tests/protocols/2026-09-14-erhebung-devin-werkzeuge.md +267 -0
- package/.koolie/core/tests/protocols/2026-09-14-erhebung-skillaufruf.md +238 -0
- package/.koolie/core/tests/protocols/2026-09-14-gegenpruefung-pruefregister.md +156 -0
- package/.koolie/core/tests/protocols/2026-09-14-gegenpruefung-schlitzdeckung.md +206 -0
- package/.koolie/core/tests/protocols/2026-09-14-gegenpruefung-skillwahl.md +127 -0
- package/.koolie/core/tests/protocols/2026-09-14-migrationslauf-pilot.md +134 -0
- package/.koolie/core/tests/protocols/2026-09-14-wirkungsnachweise-0.41.0.md +175 -0
- package/.koolie/core/tests/protocols/2026-09-14-wirkungsnachweise-0.42.0.md +180 -0
- package/.koolie/core/tests/protocols/2026-09-14-wirkungsnachweise-0.43.0.md +165 -0
- package/.koolie/core/tests/protocols/2026-09-14-wirkungsnachweise-0.44.0.md +130 -0
- package/.koolie/core/tests/protocols/2026-09-15-gegenpruefung-d11-zaehlregeln.md +311 -0
- package/.koolie/core/tests/protocols/2026-09-15-gegenpruefung-modulstatus.md +524 -0
- package/.koolie/core/tests/protocols/2026-09-15-gegenpruefung-nicht-skill-traeger.md +225 -0
- package/.koolie/core/tests/protocols/2026-09-15-gegenpruefung-restliche-nicht-skill-traeger.md +345 -0
- package/.koolie/core/tests/protocols/2026-09-15-gegenpruefung-strukturentscheidungen.md +392 -0
- package/.koolie/core/tests/protocols/2026-09-15-herrichtung-uebungsrepositorium.md +213 -0
- package/.koolie/core/tests/protocols/2026-09-15-migrationslauf-pilot-0.46.0.md +143 -0
- package/.koolie/core/tests/protocols/2026-09-15-wirkungsnachweise-0.45.0.md +127 -0
- package/.koolie/core/tests/protocols/2026-09-15-wirkungsnachweise-0.46.0.md +193 -0
- package/.koolie/core/tests/protocols/2026-09-15-wirkungsnachweise-0.47.0.md +149 -0
- package/.koolie/core/tests/protocols/2026-09-15-wirkungsnachweise-0.49.0.md +202 -0
- package/.koolie/core/tests/protocols/2026-09-15-wirkungsnachweise-0.50.0.md +183 -0
- package/.koolie/core/tests/protocols/2026-09-15-wirkungsnachweise-0.51.0.md +202 -0
- package/.koolie/core/tests/protocols/2026-09-15-wirkungsnachweise-0.52.0.md +168 -0
- package/.koolie/core/tests/protocols/2026-09-16-AP2-zielversion-devin-desktop.md +231 -0
- package/.koolie/core/tests/protocols/2026-09-16-wirkungsnachweise-0.53.0.md +350 -0
- package/.koolie/core/tests/protocols/2026-09-17-nachtrag-migrationshinweis-0.54.1.md +121 -0
- package/.koolie/core/tests/protocols/2026-09-17-sitzungstest-pi-ds.md +523 -0
- package/.koolie/core/tests/protocols/2026-09-17-sitzungstest-schranken.md +433 -0
- package/.koolie/core/tests/protocols/2026-09-17-wirkungsnachweise-0.54.0.md +159 -0
- package/.koolie/core/tests/protocols/2026-09-18-FW-AK-01.md +442 -0
- package/.koolie/core/tests/protocols/2026-09-18-FW-KO-05.md +231 -0
- package/.koolie/core/tests/protocols/2026-09-18-herrichtung-uebungsrepositorium.md +273 -0
- package/.koolie/core/tests/protocols/2026-09-18-nachtrag-preis-umbenennung-0.56.1.md +102 -0
- package/.koolie/core/tests/protocols/2026-09-18-sitzungstest-5.md +349 -0
- package/.koolie/core/tests/protocols/2026-09-18-sitzungstest-ne-sc.md +430 -0
- package/.koolie/core/tests/protocols/2026-09-18-sitzungstest-pi-ds-2.md +499 -0
- package/.koolie/core/tests/protocols/2026-09-18-vorbedingungen-sitzungstest-5-zweiter-durchgang.md +170 -0
- package/.koolie/core/tests/protocols/2026-09-18-vorbedingungen-testblaetter.md +184 -0
- package/.koolie/core/tests/protocols/2026-09-18-wirkungsnachweise-0.55.0.md +202 -0
- package/.koolie/core/tests/protocols/2026-09-18-wirkungsnachweise-0.56.0.md +135 -0
- package/.koolie/core/tests/protocols/2026-09-18-wirkungsnachweise-0.56.2.md +154 -0
- package/.koolie/core/tests/protocols/2026-09-18-wirkungsnachweise-0.57.0.md +228 -0
- package/.koolie/core/tests/protocols/2026-09-18-wirkungsnachweise-0.57.1.md +262 -0
- package/.koolie/core/tests/protocols/2026-09-18-wirkungsnachweise-0.58.0.md +135 -0
- package/.koolie/core/tests/protocols/2026-09-18-wirkungsnachweise-0.59.0.md +150 -0
- package/.koolie/core/tests/protocols/2026-09-18-wirkungsnachweise-0.60.0.md +340 -0
- package/.koolie/core/tests/protocols/2026-09-19-herrichtung-buendel-4.md +235 -0
- package/.koolie/core/tests/protocols/2026-09-19-k77-zurechenbarkeit.md +236 -0
- package/.koolie/core/tests/protocols/2026-09-19-pruefapparat-filter.md +50 -0
- package/.koolie/core/tests/protocols/2026-09-19-pruefmittelwort-und-buendelschnitt.md +239 -0
- package/.koolie/core/tests/protocols/2026-09-19-sechzehnte-praeparation.md +135 -0
- package/.koolie/core/tests/protocols/2026-09-19-testblaetter-buendel-1.md +250 -0
- package/.koolie/core/tests/protocols/2026-09-19-testblaetter-buendel-2.md +229 -0
- package/.koolie/core/tests/protocols/2026-09-19-testblaetter-buendel-3.md +293 -0
- package/.koolie/core/tests/protocols/2026-09-19-vorbedingungen-buendel-2.md +236 -0
- package/.koolie/core/tests/protocols/2026-09-19-vorbedingungen-buendel-3.md +253 -0
- package/.koolie/core/tests/protocols/2026-09-19-vorbedingungen-buendel-4.md +138 -0
- package/.koolie/core/tests/protocols/2026-09-20-messapparat-buendel-4.md +433 -0
- package/.koolie/core/tests/protocols/2026-09-20-testblaetter-buendel-4.md +321 -0
- package/.koolie/core/tests/protocols/2026-09-20-uebergabe-im-release-commit.md +146 -0
- package/.koolie/core/tests/protocols/2026-09-20-vorbedingungen-nachlauf-b4.md +259 -0
- package/.koolie/core/tests/protocols/2026-09-21-arbeitsplatz-im-kern.md +127 -0
- package/.koolie/core/tests/protocols/2026-09-21-nachlauf-buendel-4.md +157 -0
- package/.koolie/core/tests/protocols/2026-09-21-vorbedingungen-buendel-5.md +247 -0
- package/.koolie/core/tests/protocols/2026-09-21-wiederaufnahme-nachlauf-b4.md +190 -0
- package/.koolie/core/tests/protocols/2026-09-22-ap2-rest-devin-desktop.md +614 -0
- package/.koolie/core/tests/protocols/2026-09-22-hauptdokument-ap11.md +443 -0
- package/.koolie/core/tests/protocols/2026-09-22-herrichtung-buendel-5.md +224 -0
- package/.koolie/core/tests/protocols/2026-09-22-messtag-buendel-5.md +327 -0
- package/.koolie/core/tests/protocols/2026-09-22-quellenzuordnung-matrixzeilen.md +230 -0
- package/.koolie/core/tests/protocols/2026-09-22-sammelzellen-zentraler-katalog.md +354 -0
- package/.koolie/core/tests/protocols/2026-09-22-umbenennung-koolie.md +296 -0
- package/.koolie/core/tests/protocols/2026-09-22-verify-marker-abschaffen.md +283 -0
- package/.koolie/core/tests/protocols/2026-09-22-vortrag-und-name.md +261 -0
- package/.koolie/core/tests/protocols/2026-09-22-wirkungsnachweise-0.86.0.md +158 -0
- package/.koolie/core/tests/protocols/2026-09-23-archiv-zeilenenden.md +113 -0
- package/.koolie/core/tests/protocols/2026-09-23-bau-openai-codex.md +168 -0
- package/.koolie/core/tests/protocols/2026-09-23-chronik-und-vorlage.md +224 -0
- package/.koolie/core/tests/protocols/2026-09-23-erhebung-openai-codex.md +309 -0
- package/.koolie/core/tests/protocols/2026-09-23-freigabelauf-1.0.0-vorbereitung.md +119 -0
- package/.koolie/core/tests/protocols/2026-09-23-freigabelauf-1.0.0.md +150 -0
- package/.koolie/core/tests/protocols/2026-09-23-gegenzeichnung-rollenfrage.md +198 -0
- package/.koolie/core/tests/protocols/2026-09-23-reihenfolge-des-hebens.md +220 -0
- package/.koolie/core/tests/protocols/2026-09-23-word-fassung-und-blinder-fleck.md +307 -0
- package/.koolie/core/tests/protocols/2026-09-24-kopierweg-kern.md +98 -0
- package/.koolie/core/tests/protocols/2026-09-24-overlay-werte-einordnung.md +111 -0
- package/.koolie/core/tests/protocols/2026-09-24-pfadlisten-nul-getrennt.md +128 -0
- package/.koolie/core/tests/protocols/2026-09-24-uebergabe-lokal.md +85 -0
- package/.koolie/core/tests/protocols/2026-09-25-code-pack-posten.md +86 -0
- package/.koolie/core/tests/protocols/2026-09-25-dokumentationsstandard.md +101 -0
- package/.koolie/core/tests/protocols/2026-09-25-installer-je-zielsystem.md +134 -0
- package/.koolie/core/tests/protocols/2026-09-25-klasse-b-core-laufzeit.md +126 -0
- package/.koolie/core/tests/protocols/2026-09-25-klasse-b-governance.md +133 -0
- package/.koolie/core/tests/protocols/2026-09-25-klasse-b-skills.md +91 -0
- package/.koolie/core/tests/protocols/2026-09-25-lieferumfang.md +76 -0
- package/.koolie/core/tests/protocols/2026-09-25-overlay-muster-dokumente.md +107 -0
- package/.koolie/core/tests/protocols/2026-09-25-overlay-muster-general.md +100 -0
- package/.koolie/core/tests/protocols/2026-09-25-regel-register-posten.md +87 -0
- package/.koolie/core/tests/protocols/2026-09-26-attributionszeile.md +83 -0
- package/.koolie/core/tests/protocols/2026-09-26-auffindbarkeit.md +85 -0
- package/.koolie/core/tests/protocols/2026-09-26-bau-cursor.md +68 -0
- package/.koolie/core/tests/protocols/2026-09-26-bau-kiro.md +75 -0
- package/.koolie/core/tests/protocols/2026-09-26-mehrprojekt-tokenlast.md +174 -0
- package/.koolie/core/tests/protocols/2026-09-26-regelablage-pfadtoken.md +133 -0
- package/.koolie/core/tests/protocols/2026-09-26-skill-anweisungen.md +111 -0
- package/.koolie/core/tests/protocols/2026-09-26-testblaetter-modellwechsel.md +106 -0
- package/.koolie/core/tests/protocols/2026-09-27-mandat-und-reibung.md +58 -0
- package/.koolie/core/tests/protocols/2026-09-28-mcp-anbindung.md +72 -0
- package/.koolie/core/tests/protocols/2026-09-29-messapparat.md +75 -0
- package/.koolie/core/tests/protocols/2026-09-29-powershell.md +58 -0
- package/.koolie/core/tests/protocols/2026-09-29-pruefwerkzeuge.md +64 -0
- package/.koolie/core/tests/protocols/2026-09-29-registerpflege.md +228 -0
- package/.koolie/core/tests/protocols/2026-09-29-schutzschicht.md +95 -0
- package/.koolie/core/tests/protocols/2026-09-30-einsatzarchitektur.md +104 -0
- package/.koolie/core/tests/protocols/2026-09-30-modi-ausnahmen.md +77 -0
- package/.koolie/core/tests/protocols/2026-09-30-nachlauf-banner.md +85 -0
- package/.koolie/core/tests/protocols/2026-09-30-paketquellen.md +65 -0
- package/.koolie/core/tests/protocols/2026-09-30-pfadsemantik.md +79 -0
- package/.koolie/core/tests/protocols/2026-10-01-auftritt-und-suche.md +58 -0
- package/.koolie/core/tests/protocols/2026-10-01-befehl-im-projektverzeichnis.md +47 -0
- package/.koolie/core/tests/protocols/2026-10-01-erste-veroeffentlichung.md +60 -0
- package/.koolie/core/tests/protocols/2026-10-01-modusbindung-messfragen.md +107 -0
- package/.koolie/core/tests/protocols/README.md +14 -0
- package/.koolie/core/tests/scripts/hook-check-secrets.py +1307 -0
- package/.koolie/core/tests/scripts/hook-overlay-status.py +120 -0
- package/.koolie/core/tests/scripts/mermaid_renderer.py +67 -0
- package/.koolie/core/tests/scripts/overlay_status.py +130 -0
- package/.koolie/core/tests/scripts/probe-pruefungen.py +110 -0
- package/.koolie/core/tests/scripts/pruefungen/__init__.py +4 -0
- package/.koolie/core/tests/scripts/pruefungen/berechtigungen.py +1559 -0
- package/.koolie/core/tests/scripts/pruefungen/bestand.py +1433 -0
- package/.koolie/core/tests/scripts/pruefungen/dokumente.py +1262 -0
- package/.koolie/core/tests/scripts/pruefungen/gemeinsam.py +784 -0
- package/.koolie/core/tests/scripts/pruefungen/hooks.py +1188 -0
- package/.koolie/core/tests/scripts/pruefungen/overlay.py +1251 -0
- package/.koolie/core/tests/scripts/pruefungen/packs.py +1314 -0
- package/.koolie/core/tests/scripts/pruefungen/register.py +950 -0
- package/.koolie/core/tests/scripts/pruefungen/testkatalog.py +1202 -0
- package/.koolie/core/tests/scripts/pruefungen/werkzeuge.py +957 -0
- package/.koolie/core/tests/scripts/sonden/__init__.py +4 -0
- package/.koolie/core/tests/scripts/sonden/apparat.py +653 -0
- package/.koolie/core/tests/scripts/sonden/teil01_grundbestand_und_installation.py +999 -0
- package/.koolie/core/tests/scripts/sonden/teil02_packs_mandat_mcp.py +942 -0
- package/.koolie/core/tests/scripts/sonden/teil03_pruefungen_26_bis_36.py +1184 -0
- package/.koolie/core/tests/scripts/sonden/teil04_pruefungen_37_bis_45.py +1491 -0
- package/.koolie/core/tests/scripts/sonden/teil05_pruefungen_46_bis_55.py +1447 -0
- package/.koolie/core/tests/scripts/sonden/teil06_pruefungen_57_bis_65.py +739 -0
- package/.koolie/core/tests/scripts/sonden/teil07_overlay_und_lieferung.py +1014 -0
- package/.koolie/core/tests/scripts/sonden/teil08_pruefungen_66_bis_80.py +1325 -0
- package/.koolie/core/tests/scripts/sonden/teil09_pruefmittel_81_und_82.py +505 -0
- package/.koolie/core/tests/scripts/sonden/teil10_pruefungen_83_bis_95.py +1218 -0
- package/.koolie/core/tests/scripts/sonden/teil11_pruefungen_104_und_105.py +149 -0
- package/.koolie/core/tests/scripts/sonden/teil12_pruefungen_106_und_107.py +136 -0
- package/.koolie/core/tests/scripts/sonden/teil13_pfad_und_mustersemantik.py +150 -0
- package/.koolie/core/tests/scripts/sonden/teil14_modi_ausnahmen_skills.py +204 -0
- package/.koolie/core/tests/scripts/sonden/teil15_banner_und_nachlauf.py +193 -0
- package/.koolie/core/tests/scripts/sonden/teil16_koexistenz.py +114 -0
- package/.koolie/core/tests/scripts/sonden/teil17_paketquellen.py +115 -0
- package/.koolie/core/tests/scripts/sonden/teil18_modusbindung_m3_m5.py +113 -0
- package/.koolie/core/tests/scripts/validate-framework.py +1104 -0
- package/.koolie/core/tests/scripts/validate-output.py +296 -0
- package/.koolie/core/wirksamkeit.py +430 -0
- package/CONTRIBUTING.md +119 -0
- package/LICENSE +674 -0
- package/QUICKSTART.en.md +135 -0
- package/QUICKSTART.md +129 -0
- package/README.en.md +108 -0
- package/README.md +107 -0
- package/install.cmd +44 -0
- package/install.command +46 -0
- package/package.json +21 -0
- package/paketquellen/README.md +41 -0
- package/paketquellen/bauen.py +411 -0
- package/paketquellen/koolie.cmd +23 -0
- package/paketquellen/koolie_befehl.py +82 -0
- package/paketquellen/npm/koolie.js +26 -0
|
@@ -0,0 +1,1202 @@
|
|
|
1
|
+
"""Testkatalog und Testblaetter: K3-Kategorien, Grenzfaelle, Praeparationsregister,
|
|
2
|
+
Skillaufruf, Pruefmittel, Skillversion, Nummernverweise, Ausgabemarken, Ergebnisstatus,
|
|
3
|
+
Belegquelle, Aenderungsart und Ergebnisstand.
|
|
4
|
+
|
|
5
|
+
Pruefungen 29, 30, 44, 49, 61, 62, 63, 64, 65, 73, 95 und 103. Teil des Validators
|
|
6
|
+
validate-framework.py, seit 1.19.1 nach Gegenstand in Module geteilt (K-174). Das
|
|
7
|
+
Register aller Pruefungen steht im Kopfkommentar des Einstiegs, die Grenze jeder
|
|
8
|
+
einzelnen in ihrem Kopfkommentar hier."""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import re
|
|
13
|
+
|
|
14
|
+
from .gemeinsam import (
|
|
15
|
+
_client_packs, _tabellenspalte, _ueb_katalogdateien, err, iter_text_files, KERN,
|
|
16
|
+
NEUTRAL_CHRONIK, NEUTRAL_CHRONIK_BASENAMES, NEUTRAL_DOKUMENT, P73_ZEILE_RE, read,
|
|
17
|
+
skill_dirs, tabellenzellen, TBD_RE, warn)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Pruefung 29: Kurzform und Langform fuehren dieselben K3-Kategorien, unbedingt.
|
|
21
|
+
#
|
|
22
|
+
# Die Kategorien aus Abschnitt 2.1 sind ebenenfest (D-52). Zwei Fehlerbilder sind moeglich
|
|
23
|
+
# und beide sind vorgekommen: eine Kategorie fehlt in einer Fassung - die Kurzform, die in
|
|
24
|
+
# jede Sitzung laedt, fuehrte bis 0.31.0 nur sechs von acht -, oder eine Kategorie traegt
|
|
25
|
+
# eine Bedingung, wie die interne Adresse, die "sofern nicht im Overlay als K1 eingestuft"
|
|
26
|
+
# ausgenommen war. Beides prueft diese Funktion an denselben fuenf Traegern.
|
|
27
|
+
K3_KATEGORIEN = (
|
|
28
|
+
("Secrets und Zugangsdaten", r"Secret|Zugangsdaten"),
|
|
29
|
+
("personenbezogene Echtdaten", r"personenbezogene Echtdaten"),
|
|
30
|
+
("Produktionsdaten", r"Produktionsdaten"),
|
|
31
|
+
("Kunden- und Behördendokumente", r"Behörden"),
|
|
32
|
+
("Sicherheitskonfigurationen", r"Sicherheitskonfiguration"),
|
|
33
|
+
("interne Adressen und Umgebungskennungen", r"interne[nr]? Adressen"),
|
|
34
|
+
("als vertraulich eingestufte Inhalte", r"vertraulich"),
|
|
35
|
+
("Inhalte anderer Projekte", r"anderer Projekte|anderen Projekten|Fremdprojekte"),
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Eine Bedingung in einer unbedingten Liste. "es sei denn" stand in Abschnitt 2.2.
|
|
39
|
+
K3_BEDINGUNG_RE = re.compile(
|
|
40
|
+
r"sofern nicht|sofern es nicht|es sei denn|außer wenn|soweit nicht|sofern kein", re.I)
|
|
41
|
+
|
|
42
|
+
# Je Traeger: Pfad, Startanker, Endanker (None = bis Zeilenende des Startankers).
|
|
43
|
+
K3_TRAEGER = (
|
|
44
|
+
(KERN + "/framework/core/02-privacy.md", "### 2.1 Immer K3", "### 2.2"),
|
|
45
|
+
(KERN + "/framework/runtime/root-instruction.md", "- Immer K3", None),
|
|
46
|
+
(KERN + "/framework/runtime/rules/10-privacy-security.md", "| K3 |", None),
|
|
47
|
+
(KERN + "/decision-trees/01-context-allowed.md", "1. **K3-Prüfung:**", "\n2. "),
|
|
48
|
+
(KERN + "/checklists/02-privacy-context.md", "K3-Kategorien geprüft", None),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def check_k3_kategorien(root: str) -> None:
|
|
53
|
+
"""Pruefung 29 (D-52): Dieselbe K3-Liste in jeder Fassung, ohne Bedingung.
|
|
54
|
+
|
|
55
|
+
Belegt Uebereinstimmung der Kategorien, nicht die Gleichheit der Formulierungen - eine
|
|
56
|
+
Kurzform darf kuerzer sein, aber keine Kategorie weglassen und keine an eine Bedingung
|
|
57
|
+
binden. Was die Pruefung nicht leistet: Sie sieht nicht, ob ein KI-Client die Liste
|
|
58
|
+
auch anwendet. Das ist FW-KO-05, ein Dokumentenreview ueber die Fassungen
|
|
59
|
+
(.koolie/core/tests/EDGE_CASES.md); ob ein KI-Client die Liste anwendet, misst
|
|
60
|
+
kein Testfall des Katalogs - das ist K-60 (D-148).
|
|
61
|
+
"""
|
|
62
|
+
for rel, start, ende in K3_TRAEGER:
|
|
63
|
+
pfad = os.path.join(root, rel.replace("/", os.sep))
|
|
64
|
+
if not os.path.isfile(pfad):
|
|
65
|
+
err(f"{rel}: fehlt - diese Datei fuehrt die K3-Kategorien und wird gegen die "
|
|
66
|
+
f"uebrigen Fassungen geprueft (D-52)")
|
|
67
|
+
continue
|
|
68
|
+
text = read(pfad).replace("\r\n", "\n")
|
|
69
|
+
pos = text.find(start)
|
|
70
|
+
if pos < 0:
|
|
71
|
+
err(f"{rel}: Der Anker '{start}' ist nicht mehr auffindbar. Ohne ihn prueft "
|
|
72
|
+
f"diese Pruefung nichts - sie wuerde leise bestehen (D-23)")
|
|
73
|
+
continue
|
|
74
|
+
if ende:
|
|
75
|
+
bis = text.find(ende, pos + len(start))
|
|
76
|
+
bereich = text[pos:bis if bis > 0 else len(text)]
|
|
77
|
+
else:
|
|
78
|
+
bis = text.find("\n", pos)
|
|
79
|
+
bereich = text[pos:bis if bis > 0 else len(text)]
|
|
80
|
+
for name, muster in K3_KATEGORIEN:
|
|
81
|
+
if not re.search(muster, bereich):
|
|
82
|
+
err(f"{rel}: Die K3-Liste nennt die Kategorie '{name}' nicht. Alle acht "
|
|
83
|
+
f"Kategorien aus Abschnitt 2.1 von "
|
|
84
|
+
f"{KERN}/framework/core/02-privacy.md gelten in jeder Fassung; eine "
|
|
85
|
+
f"Kurzform darf kuerzer formulieren, aber keine Kategorie weglassen "
|
|
86
|
+
f"(D-52)")
|
|
87
|
+
m = K3_BEDINGUNG_RE.search(bereich)
|
|
88
|
+
if m:
|
|
89
|
+
err(f"{rel}: Die K3-Liste traegt eine Bedingung ('{m.group(0)}'). Die "
|
|
90
|
+
f"Kategorien sind unbedingt und ebenenfest - kein Overlay, keine "
|
|
91
|
+
f"Datenschutzpruefung und kein Ausnahmeprozess kann sie freigeben "
|
|
92
|
+
f"(governance/PRIORITY_HIERARCHY.md Regel 2.4, D-52)")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# Pruefung 30: Die Grenzfalltabelle ist vollstaendig und deckt jede Entscheidung ab.
|
|
96
|
+
#
|
|
97
|
+
# Das Abnahmekriterium des Reviews zu B07 und B09 verlangt Beispiele mit erwarteter
|
|
98
|
+
# Entscheidung. Eine Tabelle, in der eine Spalte leer bleibt oder eine Entscheidung
|
|
99
|
+
# unbelegt ist, sieht aus wie ein Nachweis und ist keiner. Die Anzahl steht im Steckbrief
|
|
100
|
+
# und wird nachgezaehlt: In diesem Projekt war eine Zahl schon oefter zu klein.
|
|
101
|
+
GRENZFALL_DATEI = KERN + "/tests/EDGE_CASES.md"
|
|
102
|
+
GRENZFALL_SPALTEN = 7
|
|
103
|
+
GRENZFALL_ENTSCHEIDUNGEN = ("D-52", "D-53", "D-54", "D-55", "D-56", "D-59",
|
|
104
|
+
"D-61", "D-63", "D-64", "D-66", "D-67", "D-72")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def check_grenzfaelle(root: str) -> None:
|
|
108
|
+
"""Pruefung 30: Vollstaendigkeit der Grenzfalltabelle (CR-2026-052, CR-2026-053)."""
|
|
109
|
+
pfad = os.path.join(root, GRENZFALL_DATEI.replace("/", os.sep))
|
|
110
|
+
if not os.path.isfile(pfad):
|
|
111
|
+
err(f"{GRENZFALL_DATEI}: fehlt. Die entschiedenen Regelkonflikte brauchen ihre "
|
|
112
|
+
f"Grenzfaelle als Referenz - das ist das Abnahmekriterium des Reviews zu B07 "
|
|
113
|
+
f"und B09")
|
|
114
|
+
return
|
|
115
|
+
text = read(pfad)
|
|
116
|
+
m = re.search(r"\|\s*Anzahl der Grenzfälle\s*\|\s*(\d+)\s*\|", text)
|
|
117
|
+
if not m:
|
|
118
|
+
err(f"{GRENZFALL_DATEI}: Der Steckbrief nennt keine Anzahl der Grenzfaelle. Ohne "
|
|
119
|
+
f"sie faellt eine geloeschte Zeile nicht auf")
|
|
120
|
+
return
|
|
121
|
+
erwartet = int(m.group(1))
|
|
122
|
+
zeilen = [z for z in text.splitlines() if re.match(r"\|\s*G-\d+\s*\|", z)]
|
|
123
|
+
if len(zeilen) != erwartet:
|
|
124
|
+
err(f"{GRENZFALL_DATEI}: {len(zeilen)} Grenzfallzeilen, der Steckbrief nennt "
|
|
125
|
+
f"{erwartet}. Eine Zahl, die nicht stimmt, ist kein Nachweis")
|
|
126
|
+
for zeile in zeilen:
|
|
127
|
+
zellen = tabellenzellen(zeile)
|
|
128
|
+
kennung = zellen[0] if zellen else "?"
|
|
129
|
+
if len(zellen) != GRENZFALL_SPALTEN:
|
|
130
|
+
err(f"{GRENZFALL_DATEI}: Grenzfall {kennung} hat {len(zellen)} Spalten statt "
|
|
131
|
+
f"{GRENZFALL_SPALTEN} (Nr., Grenzfall, Entscheidung, Betriebsmodus, "
|
|
132
|
+
f"Kontrollstufe, Rollen, Fundstelle)")
|
|
133
|
+
continue
|
|
134
|
+
for nr, zelle in enumerate(zellen, 1):
|
|
135
|
+
if not zelle or zelle in ("-", "–"):
|
|
136
|
+
err(f"{GRENZFALL_DATEI}: Grenzfall {kennung}, Spalte {nr} ist leer. Jede "
|
|
137
|
+
f"Spalte ist Teil der Einstufung; eine leere Spalte laesst offen, was "
|
|
138
|
+
f"gilt")
|
|
139
|
+
if TBD_RE.search(zelle):
|
|
140
|
+
err(f"{GRENZFALL_DATEI}: Grenzfall {kennung}, Spalte {nr} traegt einen "
|
|
141
|
+
f"offenen <TBD>-Wert. Ein Grenzfall ohne Entscheidung ist keiner")
|
|
142
|
+
for d in GRENZFALL_ENTSCHEIDUNGEN:
|
|
143
|
+
if not any(d in z for z in zeilen):
|
|
144
|
+
err(f"{GRENZFALL_DATEI}: Keine Grenzfallzeile verweist auf {d}. Jede "
|
|
145
|
+
f"entschiedene Auslegungsfrage braucht mindestens einen Grenzfall, sonst "
|
|
146
|
+
f"ist das Abnahmekriterium des Reviews nicht eingeloest")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
# ---------------------------------------------------------------------------
|
|
150
|
+
# Pruefung 44: Das Register der Uebungspraeparationen und die Vorbedingungen des
|
|
151
|
+
# Testkatalogs decken sich
|
|
152
|
+
# ---------------------------------------------------------------------------
|
|
153
|
+
#
|
|
154
|
+
# ANLASS. Gemessen am 2026-09-14 (CR-2026-067, Befund 2): onboarding/exercises/README.md
|
|
155
|
+
# verlangte DREI Koeder. Abgezaehlt gegen die Vorbedingungen des Testkatalogs braucht ein
|
|
156
|
+
# fahrbares Uebungsrepositorium SIEBEN Praeparationen fuer NEUN Testfaelle - dazu eine
|
|
157
|
+
# .env-Testdatei (FW-DS-02), einen praeparierten Codekommentar (FW-PI-02), eine Injektion
|
|
158
|
+
# in einer Testdatei (SK-006-N04) und einen Regeltext mit bewusstem Widerspruch
|
|
159
|
+
# (FW-KO-03). Keine der vier stand in der Liste, und der Katalog fuehrte alle neun Faelle
|
|
160
|
+
# als 'offen', also als fahrbar. EINE ZUSAGE OHNE DEN MECHANISMUS DAHINTER - der
|
|
161
|
+
# wiederkehrende Befundtyp dieses Projekts, diesmal an seinem eigenen Pruefstand.
|
|
162
|
+
#
|
|
163
|
+
# WIE DIE ZUORDNUNG ENTSTEHT (E5). Jede Praeparation traegt eine Kennung UEB-NN. Sie steht
|
|
164
|
+
# im Register in der ersten Spalte und in der Vorbedingungszelle jedes Testfalls, der sie
|
|
165
|
+
# braucht. Der Vergleich laeuft ueber die Kennung und ist damit exakt - nicht ueber
|
|
166
|
+
# Stichwoerter wie "Koeder" oder "praepariert", die Pruefung 29 als Bauform schon einmal
|
|
167
|
+
# teuer bezahlt hat: Sie erkennt nur bekannte Bedingungswoerter.
|
|
168
|
+
#
|
|
169
|
+
# WARUM UEB- UND NICHT P1 (E5). P1 und P3 sind im Kern als Prinzipienkennungen vergeben
|
|
170
|
+
# (framework/core/05-working-model.md). Eine zweite Bedeutung desselben Zeichens in
|
|
171
|
+
# derselben Dokumentfamilie ist ein Fehler, den dieses Projekt schon gemacht hat: Am
|
|
172
|
+
# 2026-09-13 trug eine Gegenprobe die synthetische Kennung G-18 - dieselbe, die 0.36.0
|
|
173
|
+
# wirklich vergeben hat.
|
|
174
|
+
#
|
|
175
|
+
# BEIDE RICHTUNGEN (E6). Eine Kennung im Katalog ohne Registereintrag ist ein Tippfehler
|
|
176
|
+
# oder eine unregistrierte Praeparation; eine Kennung im Register, die kein Testfall
|
|
177
|
+
# braucht, ist eine tote Praeparation, die jemand pflegt. Die dezentralen TESTS.md zaehlen
|
|
178
|
+
# mit - Verfahren Nr. 6 des Katalogs erklaert sie zu seinem Teil.
|
|
179
|
+
#
|
|
180
|
+
# GRENZE, UND SIE IST DIE WICHTIGE. Diese Pruefung faengt NICHT den Fall, der sie
|
|
181
|
+
# ausgeloest hat: einen Testfall, der eine Praeparation braucht und keine Kennung nennt.
|
|
182
|
+
# Sie verhindert seine WIEDERHOLUNG nur, soweit die Kennung gesetzt wird - dieselbe
|
|
183
|
+
# Ehrlichkeit wie Gegenstand 2 von Pruefung 38 (er zaehlt Deklarationen, nicht
|
|
184
|
+
# Richtigkeit) und wie Pruefung 40 (sie zaehlt Nennungen, nicht Pruefungen).
|
|
185
|
+
#
|
|
186
|
+
# ZWEITE GRENZE. Sie gleicht zwei Register ab, nicht ein Register gegen die Wirklichkeit.
|
|
187
|
+
# Ob die Praeparation UEB-02 im Uebungsrepositorium wirklich liegt, kann kein Validator
|
|
188
|
+
# DIESES Repositoriums feststellen: Das Uebungsrepositorium liegt ausserhalb. Das ist eine
|
|
189
|
+
# Enthaltung, keine Stille.
|
|
190
|
+
UEB_REGISTER = "onboarding/exercises/README.md"
|
|
191
|
+
UEB_ANKER = "### Register der Präparationen"
|
|
192
|
+
UEB_KENNUNG = re.compile(r"\bUEB-\d{2}\b")
|
|
193
|
+
# Gegenstand 3 (D-131). Die Spalte wird ueber ihre UEBERSCHRIFT gefunden, nicht ueber
|
|
194
|
+
# ihre Nummer: Eine Erkennungsregel fuer eine Dokumentstruktur gehoert an die Stellung,
|
|
195
|
+
# nicht an eine Zaehlung, die die naechste eingeschobene Spalte verschiebt.
|
|
196
|
+
UEB_BELEGSPALTE = "Wie sie belegt ist"
|
|
197
|
+
# Gegenstand 4 (D-173). Die Spalten werden ueber ihre UEBERSCHRIFT gefunden, die
|
|
198
|
+
# Testfallspalte des Registers ist die LETZTE. Der Zuschnitt trennt die Vorbedingung
|
|
199
|
+
# von ihrer Geschichte am ersten Vermerkzeichen: Was davor steht, ist die Bedingung;
|
|
200
|
+
# was dahinter steht, ist ihre Herkunft. FW-NE-02 nennt UEB-06 hinter dem Vermerk
|
|
201
|
+
# ("UEB-08 verdraengt UEB-06"), ohne es zu verlangen - wer die ganze Zelle liest,
|
|
202
|
+
# meldet diese Zeile mit.
|
|
203
|
+
UEB_VORBEDINGUNGSSPALTE = "Vorbedingung"
|
|
204
|
+
UEB_VERMERK_RE = re.compile("[\U0001F534\U0001F7E2\U0001F195⚠]")
|
|
205
|
+
UEB_FALL_RE = re.compile(r"\b(?:FW|SK|RE)-[A-Z0-9-]+\b")
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _vor_dem_vermerk(zelle: str) -> str:
|
|
209
|
+
"""Der Teil einer Tabellenzelle vor dem ersten Vermerkzeichen."""
|
|
210
|
+
treffer = UEB_VERMERK_RE.search(zelle)
|
|
211
|
+
return zelle[:treffer.start()] if treffer else zelle
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _ueb_gebraucht_je_vorbedingung(root: str) -> dict:
|
|
215
|
+
"""{UEB-NN: {Testfallkennung}} - nur aus der Vorbedingungsspalte, vor dem Vermerk."""
|
|
216
|
+
raus: dict = {}
|
|
217
|
+
for rel in _ueb_katalogdateien(root):
|
|
218
|
+
pfad = os.path.join(root, *rel.split(os.sep))
|
|
219
|
+
if not os.path.exists(pfad):
|
|
220
|
+
continue
|
|
221
|
+
i_vb = -1
|
|
222
|
+
for zeile in read(pfad).splitlines():
|
|
223
|
+
if not zeile.lstrip().startswith("|"):
|
|
224
|
+
continue
|
|
225
|
+
if UEB_VORBEDINGUNGSSPALTE in zeile and "Prüfmethode" in zeile:
|
|
226
|
+
i_vb = _tabellenspalte(zeile, UEB_VORBEDINGUNGSSPALTE)
|
|
227
|
+
continue
|
|
228
|
+
if i_vb < 0:
|
|
229
|
+
continue
|
|
230
|
+
zellen = tabellenzellen(zeile)
|
|
231
|
+
if len(zellen) <= i_vb:
|
|
232
|
+
continue
|
|
233
|
+
fall = UEB_FALL_RE.match(zellen[0].strip("`* "))
|
|
234
|
+
if not fall:
|
|
235
|
+
continue
|
|
236
|
+
for kennung in UEB_KENNUNG.findall(_vor_dem_vermerk(zellen[i_vb])):
|
|
237
|
+
raus.setdefault(kennung, set()).add(fall.group(0))
|
|
238
|
+
return raus
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def check_praeparationsregister(root: str) -> None:
|
|
242
|
+
"""Pruefung 44 (D-93): Registrierte Praeparationen und gebrauchte decken sich."""
|
|
243
|
+
pfad = os.path.join(root, KERN, *UEB_REGISTER.split("/"))
|
|
244
|
+
if not os.path.exists(pfad):
|
|
245
|
+
err(f"{KERN}/{UEB_REGISTER}: fehlt. Prüfung 44 hält dort das Register der "
|
|
246
|
+
f"Übungspräparationen gegen die Vorbedingungen des Testkatalogs (D-93)")
|
|
247
|
+
return
|
|
248
|
+
text = read(pfad)
|
|
249
|
+
if UEB_ANKER not in text:
|
|
250
|
+
err(f"{KERN}/{UEB_REGISTER}: führt kein Register mehr (gesucht: "
|
|
251
|
+
f"'{UEB_ANKER}'). Prüfung 44 hat ihren Gegenstand verloren und bestünde "
|
|
252
|
+
f"sonst leise – die Überschrift ist Teil des Nachweises (D-23, D-93)")
|
|
253
|
+
return
|
|
254
|
+
registriert = set(UEB_KENNUNG.findall(text.split(UEB_ANKER, 1)[1]))
|
|
255
|
+
if not registriert:
|
|
256
|
+
err(f"{KERN}/{UEB_REGISTER}: das Register führt keine einzige Kennung der Form "
|
|
257
|
+
f"UEB-NN – Prüfung 44 hätte nichts zu vergleichen (D-93)")
|
|
258
|
+
return
|
|
259
|
+
|
|
260
|
+
gebraucht: dict = {}
|
|
261
|
+
for rel in _ueb_katalogdateien(root):
|
|
262
|
+
pfad_k = os.path.join(root, *rel.split(os.sep))
|
|
263
|
+
if not os.path.exists(pfad_k):
|
|
264
|
+
continue
|
|
265
|
+
for kennung in UEB_KENNUNG.findall(read(pfad_k)):
|
|
266
|
+
gebraucht.setdefault(kennung, set()).add(rel.replace(os.sep, "/"))
|
|
267
|
+
|
|
268
|
+
for kennung in sorted(set(gebraucht) - registriert):
|
|
269
|
+
stellen = ", ".join(sorted(gebraucht[kennung]))
|
|
270
|
+
err(f"{stellen}: nennt die Präparation {kennung}, die das Register in "
|
|
271
|
+
f"{KERN}/{UEB_REGISTER} nicht führt. Eine Vorbedingung, die auf eine "
|
|
272
|
+
f"unregistrierte Präparation zeigt, ist eine Zusage ohne den Mechanismus "
|
|
273
|
+
f"dahinter – der Testfall gilt als fahrbar, und niemand weiß, was "
|
|
274
|
+
f"herzustellen ist (D-93)")
|
|
275
|
+
for kennung in sorted(registriert - set(gebraucht)):
|
|
276
|
+
err(f"{KERN}/{UEB_REGISTER}: führt die Präparation {kennung}, die kein Testfall "
|
|
277
|
+
f"nennt – weder der Testkatalog noch ein dezentrales Testblatt. Eine "
|
|
278
|
+
f"Präparation, die niemand braucht, wird gepflegt und nicht benutzt; "
|
|
279
|
+
f"entweder trägt ein Testfall sie in seine Vorbedingung ein, oder sie fällt "
|
|
280
|
+
f"aus dem Register (D-93)")
|
|
281
|
+
|
|
282
|
+
# --- Gegenstand 4: die zeilenweise Deckung (D-173) ------------------------------
|
|
283
|
+
# Gegenstand 1 und 2 vergleichen MENGEN ueber die ganze Datei. Sie bestehen auch
|
|
284
|
+
# dann, wenn die Kennung in der Ergebniszelle statt in der Vorbedingung steht -
|
|
285
|
+
# und dann sagt genau die Spalte, die dem Laufenden sagt, was herzustellen ist,
|
|
286
|
+
# es nicht. 0.64.0 hat fuenfzehn Blattzellen hergerichtet und die Kennung dreimal
|
|
287
|
+
# nur in den gruenen Vermerk der Ergebniszelle geschrieben; die Gegenrichtung
|
|
288
|
+
# fehlte zweimal, und das vollstaendigere Register lag AUSSERHALB des
|
|
289
|
+
# Repositoriums (im Mentorenblatt des Uebungsrepositoriums).
|
|
290
|
+
zeilen_reg = [z for z in text.split(UEB_ANKER, 1)[1].split("\n")
|
|
291
|
+
if z.strip().startswith("|")]
|
|
292
|
+
gebraucht_vb = _ueb_gebraucht_je_vorbedingung(root)
|
|
293
|
+
for zeile in zeilen_reg:
|
|
294
|
+
zellen = tabellenzellen(zeile)
|
|
295
|
+
treffer = UEB_KENNUNG.findall(zellen[0]) if zellen else []
|
|
296
|
+
if not treffer:
|
|
297
|
+
continue
|
|
298
|
+
kennung = treffer[0]
|
|
299
|
+
genannt = set(UEB_FALL_RE.findall(zellen[-1])) if len(zellen) > 1 else set()
|
|
300
|
+
misst = gebraucht_vb.get(kennung, set())
|
|
301
|
+
for fall in sorted(genannt - misst):
|
|
302
|
+
err(f"{KERN}/{UEB_REGISTER}: die Zeile {kennung} nennt den Testfall {fall}, "
|
|
303
|
+
f"dessen Vorbedingungszelle {kennung} nicht führt. Die Spalte, die sagt, "
|
|
304
|
+
f"was vor dem Lauf herzustellen ist, sagt es damit nicht – eine Nennung "
|
|
305
|
+
f"in der Ergebniszelle erreicht den Laufenden zu spät (D-93, D-173)")
|
|
306
|
+
for fall in sorted(misst - genannt):
|
|
307
|
+
err(f"{KERN}/{UEB_REGISTER}: der Testfall {fall} nennt {kennung} in seiner "
|
|
308
|
+
f"Vorbedingung, die Registerzeile {kennung} führt ihn aber nicht. Ein "
|
|
309
|
+
f"Register, das seinen Gegenstand nicht führt, ist eine Auswahl – und "
|
|
310
|
+
f"sie ist immer zu klein, nie zu groß (D-93, D-173)")
|
|
311
|
+
|
|
312
|
+
# --- Gegenstand 3: die Belegzelle (D-131) --------------------------------------
|
|
313
|
+
# UEB-06 stand dreizehn Releases lang im Register und stellte seinen Gegenstand
|
|
314
|
+
# nicht her. Der Eintrag behauptete, der Testbefehl gebe die Anweisung aus; gemessen
|
|
315
|
+
# hat das niemand, und er tut es nicht. Ein Vorhandensein belegt sich selbst, ein
|
|
316
|
+
# Fehlen nicht - und eine Praeparation, deren Gegenstand erst durch einen Lauf
|
|
317
|
+
# entsteht, ist ein Fehlen, solange niemand den Lauf gefahren hat.
|
|
318
|
+
zeilen = [z for z in text.split(UEB_ANKER, 1)[1].split("\n") if z.strip().startswith("|")]
|
|
319
|
+
kopf = next((z for z in zeilen if UEB_BELEGSPALTE in z), None)
|
|
320
|
+
if kopf is None:
|
|
321
|
+
err(f"{KERN}/{UEB_REGISTER}: die Registertabelle führt keine Spalte "
|
|
322
|
+
f"'{UEB_BELEGSPALTE}'. Gegenstand 3 der Prüfung 44 hat seinen Anker verloren "
|
|
323
|
+
f"und bestünde sonst leise – die Spaltenüberschrift ist Teil des Nachweises "
|
|
324
|
+
f"(D-23, D-131)")
|
|
325
|
+
return
|
|
326
|
+
spalte = tabellenzellen(kopf).index(UEB_BELEGSPALTE)
|
|
327
|
+
for zeile in zeilen:
|
|
328
|
+
zellen = tabellenzellen(zeile)
|
|
329
|
+
treffer = UEB_KENNUNG.findall(zellen[0]) if zellen else []
|
|
330
|
+
if not treffer:
|
|
331
|
+
continue
|
|
332
|
+
if len(zellen) <= spalte or not zellen[spalte]:
|
|
333
|
+
err(f"{KERN}/{UEB_REGISTER}: die Zeile {treffer[0]} führt keine Belegzelle "
|
|
334
|
+
f"('{UEB_BELEGSPALTE}'). Ein Registereintrag ohne Beleg ist eine Zusage "
|
|
335
|
+
f"über einen Mechanismus, den niemand ausgeführt hat – genau der Fall "
|
|
336
|
+
f"von UEB-06, der dreizehn Releases lang einen Testfall unfahrbar "
|
|
337
|
+
f"gehalten hat (D-131)")
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
# --- Pruefung 49 -------------------------------------------------------------------
|
|
342
|
+
# Die Marken stammen aus den Skillquellen des Kerns, nicht aus einer gepflegten Liste.
|
|
343
|
+
# 'triggers' ist ein Kernbegriff; die Abbildung auf das Clientfeld leistet install.py
|
|
344
|
+
# (bei claude-code 'disable-model-invocation'). Diese Pruefung fragt nach der QUELLE,
|
|
345
|
+
# damit sie unabhaengig vom installierten Pack dasselbe sagt.
|
|
346
|
+
SKILL_TRIGGER_RE = re.compile(r"^triggers:\s*$(.*?)(?=^\S|\Z)", re.M | re.S)
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def _skills_ohne_modellaufruf(root: str) -> list:
|
|
350
|
+
"""Namen der Kernskills, deren Quelle 'triggers' ohne '- model' fuehrt, sortiert.
|
|
351
|
+
|
|
352
|
+
Ein solcher Skill ist nur ueber den ausdruecklichen Aufruf einer Person erreichbar;
|
|
353
|
+
das Modell darf ihn nicht von sich aus waehlen. Gemessen am 2026-09-18: neun von
|
|
354
|
+
zwoelf (CR-2026-085, D-146).
|
|
355
|
+
"""
|
|
356
|
+
namen = []
|
|
357
|
+
for basis in (os.path.join(root, KERN, "framework", "skills"),):
|
|
358
|
+
if not os.path.isdir(basis):
|
|
359
|
+
continue
|
|
360
|
+
for name in sorted(os.listdir(basis)):
|
|
361
|
+
pfad = os.path.join(basis, name, "SKILL.md")
|
|
362
|
+
if not os.path.isfile(pfad):
|
|
363
|
+
continue
|
|
364
|
+
text = read(pfad)
|
|
365
|
+
if not text.startswith("---"):
|
|
366
|
+
continue
|
|
367
|
+
ende = text.find("---", 3)
|
|
368
|
+
if ende < 0:
|
|
369
|
+
continue
|
|
370
|
+
m = SKILL_TRIGGER_RE.search(text[3:ende])
|
|
371
|
+
if m and "- model" not in m.group(1):
|
|
372
|
+
namen.append(name)
|
|
373
|
+
return namen
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
# Gegenstand 2 (D-172). Die Uebungen und ihre Skills stammen aus der Uebungsdatei,
|
|
377
|
+
# nicht aus einer gepflegten Liste: Wer eine Uebung um einen Schritt erweitert, soll
|
|
378
|
+
# nicht daran denken muessen, eine Liste im Validator nachzuziehen.
|
|
379
|
+
P49_UEBUNGSDATEI = KERN + "/onboarding/exercises/EXERCISES.md"
|
|
380
|
+
P49_UEBUNG_RE = re.compile("Ü\\d[a-z]?")
|
|
381
|
+
P49_UEBUNG_KOPF_RE = re.compile(r"^##\s+(Ü\d)\b")
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def _uebungsskills(root: str) -> dict:
|
|
385
|
+
"""{UEn: [Skillnamen]} - abgeleitet aus den Abschnitten der Uebungsdatei.
|
|
386
|
+
|
|
387
|
+
Gelesen werden die Skillaufrufe der Form /name im Abschnitt einer Uebung. Die
|
|
388
|
+
Uebungsdatei schreibt sie durchgaengig so - sie beschreibt den Ablauf, den eine
|
|
389
|
+
PERSON geht, und genau das ist der Grund, aus dem ein Ausloeser, der sich auf sie
|
|
390
|
+
beruft, den Aufruf nicht verschweigen darf.
|
|
391
|
+
"""
|
|
392
|
+
pfad = os.path.join(root, *P49_UEBUNGSDATEI.split("/"))
|
|
393
|
+
if not os.path.isfile(pfad):
|
|
394
|
+
err(f"{P49_UEBUNGSDATEI}: fehlt. Gegenstand 2 der Prüfung 49 leitet die Skills "
|
|
395
|
+
f"jeder Übung von dort ab und hat seinen Gegenstand verloren; er bestünde "
|
|
396
|
+
f"sonst leise (D-23, D-172)")
|
|
397
|
+
return {}
|
|
398
|
+
raus: dict = {}
|
|
399
|
+
aktuell = None
|
|
400
|
+
for zeile in read(pfad).splitlines():
|
|
401
|
+
kopf = P49_UEBUNG_KOPF_RE.match(zeile.strip())
|
|
402
|
+
if kopf:
|
|
403
|
+
aktuell = kopf.group(1)
|
|
404
|
+
raus.setdefault(aktuell, [])
|
|
405
|
+
continue
|
|
406
|
+
if aktuell is None:
|
|
407
|
+
continue
|
|
408
|
+
for treffer in re.findall(r"/(fw-[a-z0-9-]+)", zeile):
|
|
409
|
+
if treffer not in raus[aktuell]:
|
|
410
|
+
raus[aktuell].append(treffer)
|
|
411
|
+
if not raus:
|
|
412
|
+
err(f"{P49_UEBUNGSDATEI}: führt keinen Abschnitt der Form '## Ü<n> …'. "
|
|
413
|
+
f"Gegenstand 2 der Prüfung 49 hat seinen Anker verloren und bestünde sonst "
|
|
414
|
+
f"leise (D-23, D-172)")
|
|
415
|
+
return raus
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def check_skillaufruf_im_katalog(root: str) -> None:
|
|
419
|
+
"""Pruefung 49 (D-146): Ein nicht modellaufrufbarer Skill steht als /name im Ausloeser."""
|
|
420
|
+
namen = _skills_ohne_modellaufruf(root)
|
|
421
|
+
if not namen:
|
|
422
|
+
err(f"{KERN}/framework/skills/: kein Skill mit 'triggers' ohne '- model' gefunden – "
|
|
423
|
+
f"Prüfung 49 leitet ihre Marken daraus ab und hat ihren Gegenstand verloren; "
|
|
424
|
+
f"sie bestünde sonst leise (D-23)")
|
|
425
|
+
return
|
|
426
|
+
uebungsskills = _uebungsskills(root)
|
|
427
|
+
alle_skills = sorted({s for liste in uebungsskills.values() for s in liste} | set(namen))
|
|
428
|
+
dateien = [os.path.join(root, KERN, "tests", "TEST_CATALOG.md")]
|
|
429
|
+
for basis in (os.path.join(root, KERN, "framework", "skills"),
|
|
430
|
+
os.path.join(root, KERN, "framework", "role-packs")):
|
|
431
|
+
for wurzel, _, files in os.walk(basis):
|
|
432
|
+
if "TESTS.md" in files:
|
|
433
|
+
dateien.append(os.path.join(wurzel, "TESTS.md"))
|
|
434
|
+
for pfad in sorted(dateien):
|
|
435
|
+
if not os.path.isfile(pfad):
|
|
436
|
+
continue
|
|
437
|
+
rel = os.path.relpath(pfad, root).replace(os.sep, "/")
|
|
438
|
+
i_ein = i_pm = -1
|
|
439
|
+
for nr, zeile in enumerate(read(pfad).splitlines(), 1):
|
|
440
|
+
if not zeile.lstrip().startswith("|"):
|
|
441
|
+
continue
|
|
442
|
+
if "Prüfmethode" in zeile and "Eingabe" in zeile:
|
|
443
|
+
i_ein = _tabellenspalte(zeile, "Eingabe")
|
|
444
|
+
i_pm = _tabellenspalte(zeile, "Prüfmethode")
|
|
445
|
+
continue
|
|
446
|
+
if i_ein < 0 or i_pm < 0:
|
|
447
|
+
continue
|
|
448
|
+
zellen = [z.strip() for z in zeile.strip().strip("|").split("|")]
|
|
449
|
+
if len(zellen) <= max(i_ein, i_pm):
|
|
450
|
+
continue
|
|
451
|
+
if "sitzung" not in zellen[i_pm]:
|
|
452
|
+
continue
|
|
453
|
+
ausloeser = zellen[i_ein]
|
|
454
|
+
for skill in namen:
|
|
455
|
+
# Nur die nackte Nennung ist ein Befund: '/name' ist der Aufruf selbst.
|
|
456
|
+
for m in re.finditer(r"(?<![/\w-])" + re.escape(skill) + r"(?![\w-])", ausloeser):
|
|
457
|
+
err(f"{rel}:{nr}: Der Auslöser nennt '{skill}' ohne den ausdrücklichen "
|
|
458
|
+
f"Aufruf. Die Quelle des Skills führt 'triggers' ohne '- model' – "
|
|
459
|
+
f"das Modell darf ihn nicht von sich aus wählen, und ein "
|
|
460
|
+
f"nicht-interaktiver Lauf bekommt eine Abweisung statt des Ablaufs. "
|
|
461
|
+
f"Schreibe '/{skill}' (D-146)")
|
|
462
|
+
break
|
|
463
|
+
# --- Gegenstand 2 (D-172): der Ausloeser, der eine UEBUNG nennt ---------
|
|
464
|
+
# Er nennt keinen Skill und erbt doch welche. FW-PO-02 verweist auf UE3,
|
|
465
|
+
# und UE3 geht durch vier Skills, die das Modell nicht waehlen darf.
|
|
466
|
+
# SCHMAL, und das ist Absicht: Gefragt wird, ob UEBERHAUPT ein
|
|
467
|
+
# ausdruecklicher Aufruf dasteht - nicht, ob es der richtige oder ob es
|
|
468
|
+
# alle sind. FW-SC-01 nennt UE3 und ruft bewusst nur deren dritten Schritt
|
|
469
|
+
# auf; eine Pruefung kann Zuschnitt nicht von Vergesslichkeit
|
|
470
|
+
# unterscheiden. Der erste Entwurf haette FW-SC-01 dreimal gemeldet.
|
|
471
|
+
# Ein ausdruecklicher Aufruf ist '/<skillname>', nicht irgendein Schraegstrich:
|
|
472
|
+
# Der Ausloeser von FW-PO-02 nennt einen PFAD, und der erste Entwurf hat
|
|
473
|
+
# '/onboarding' fuer einen Aufruf gehalten und nichts gemeldet.
|
|
474
|
+
if any(f"/{s}" in ausloeser for s in alle_skills):
|
|
475
|
+
continue
|
|
476
|
+
# Ue6c ist ein Teil von Ue6 - die Abschnittsueberschrift traegt nur die
|
|
477
|
+
# Ziffer, der Verweis zusaetzlich einen Buchstaben.
|
|
478
|
+
for uebung in sorted({t[:2] for t in P49_UEBUNG_RE.findall(ausloeser)}):
|
|
479
|
+
geerbt = sorted(set(uebungsskills.get(uebung, ())) & set(namen))
|
|
480
|
+
if not geerbt:
|
|
481
|
+
continue
|
|
482
|
+
err(f"{rel}:{nr}: Der Auslöser nennt die Übung {uebung} und damit "
|
|
483
|
+
f"deren Ablauf, der durch {', '.join(geerbt)} geht – Skills, deren "
|
|
484
|
+
f"Quelle 'triggers' ohne '- model' führt. Der Auslöser enthält "
|
|
485
|
+
f"keinen einzigen ausdrücklichen Aufruf; ein nicht-interaktiver "
|
|
486
|
+
f"Lauf bekommt eine Abweisung statt des Ablaufs. Nenne den "
|
|
487
|
+
f"Einstiegsschritt als '/name' (D-172)")
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
# --- Pruefung 103: der Stand einer Ergebniszelle (CR-2026-160, D-472, K-61) --------------
|
|
491
|
+
# ANLASS, GEMESSEN am 2026-09-18: FW-KO-02 stand seit dem 10.09. auf 'bestanden', und drei
|
|
492
|
+
# der vier Befunde, die FW-KO-05 danach fand, lagen genau in seinem Gegenstand - entstanden
|
|
493
|
+
# NACH der Abnahme. Der Testfall war nicht falsch; sein Belegstand war veraltet, und nichts
|
|
494
|
+
# meldete es.
|
|
495
|
+
#
|
|
496
|
+
# DIE FORM: Eine Ergebniszelle kann ihren Stand tragen - '[Stand: ' + zwoelf Hexziffern +
|
|
497
|
+
# '; ' + die Pfade ihres Gegenstands relativ zum Kern, durch Komma getrennt + ']'. Der Wert
|
|
498
|
+
# ist sha256 ueber Pfad und Inhalt jeder Datei in der genannten Reihenfolge, Zeilenenden auf
|
|
499
|
+
# LF gebracht; der Messapparat schreibt ihn beim Eintragen (tests/erhebungen/apparat).
|
|
500
|
+
#
|
|
501
|
+
# WAS SIE LEISTET: Weicht der Gegenstand vom Stand ab, WARNT sie - eine Aenderung ist kein
|
|
502
|
+
# Fehler, sie verlangt eine Entscheidung (neu erheben oder den Stand bestaetigen). Nennt die
|
|
503
|
+
# Marke einen Pfad, den es nicht gibt, ist das ein FEHLER: ein Stand ohne Gegenstand belegt
|
|
504
|
+
# nichts. WAS SIE NICHT LEISTET: Eine Zelle ohne Marke bleibt ungeprueft; der Altbestand
|
|
505
|
+
# traegt keine, und ihn mit geratenen Gegenstaenden nachzutragen saehe wie ein Beleg aus.
|
|
506
|
+
P103_MARKE_RE = re.compile(r"\[Stand: ([0-9a-f]{12}); ([^\]]+)\]")
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
def stand_wert(kern: str, pfade: list) -> str | None:
|
|
510
|
+
"""Der Stand ueber die Dateien eines Gegenstands - None, wenn eine fehlt."""
|
|
511
|
+
import hashlib
|
|
512
|
+
h = hashlib.sha256()
|
|
513
|
+
for pfad in pfade:
|
|
514
|
+
voll = os.path.join(kern, *pfad.split("/"))
|
|
515
|
+
if not os.path.isfile(voll):
|
|
516
|
+
return None
|
|
517
|
+
with open(voll, "rb") as fh:
|
|
518
|
+
inhalt = fh.read().replace(b"\r\n", b"\n")
|
|
519
|
+
h.update(pfad.encode("utf-8") + b"\n" + inhalt + b"\n")
|
|
520
|
+
return h.hexdigest()[:12]
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
def _p103_traeger(root: str) -> list:
|
|
524
|
+
kern = os.path.join(root, KERN)
|
|
525
|
+
dateien = [os.path.join(kern, "tests", "TEST_CATALOG.md")]
|
|
526
|
+
for basis in (os.path.join(kern, "framework", "skills"),
|
|
527
|
+
os.path.join(kern, "framework", "role-packs")):
|
|
528
|
+
for wurzel, _, files in os.walk(basis):
|
|
529
|
+
if "TESTS.md" in files:
|
|
530
|
+
dateien.append(os.path.join(wurzel, "TESTS.md"))
|
|
531
|
+
return [d for d in sorted(dateien) if os.path.exists(d)]
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
def check_ergebnisstand(root: str) -> None:
|
|
535
|
+
"""Pruefung 103 (D-472): der Stand einer Ergebniszelle gegen ihren heutigen Gegenstand."""
|
|
536
|
+
kern = os.path.join(root, KERN)
|
|
537
|
+
for pfad in _p103_traeger(root):
|
|
538
|
+
rel = os.path.relpath(pfad, root).replace(os.sep, "/")
|
|
539
|
+
for nr, zeile in enumerate(read(pfad).splitlines(), 1):
|
|
540
|
+
for m in P103_MARKE_RE.finditer(zeile):
|
|
541
|
+
gegenstand = [p.strip().strip("`") for p in m.group(2).split(",") if p.strip()]
|
|
542
|
+
wert = stand_wert(kern, gegenstand)
|
|
543
|
+
if wert is None:
|
|
544
|
+
err(f"{rel}:{nr}: die Standmarke nennt einen Gegenstand, den es nicht gibt "
|
|
545
|
+
f"({', '.join(gegenstand)}) – ein Stand ohne Gegenstand belegt nichts (D-472)")
|
|
546
|
+
elif wert != m.group(1):
|
|
547
|
+
warn(f"{rel}:{nr}: Belegstand veraltet – der Gegenstand "
|
|
548
|
+
f"({', '.join(gegenstand)}) hat sich seit der Messung geändert "
|
|
549
|
+
f"(Stand {m.group(1)}, heute {wert}); neu erheben oder den Stand "
|
|
550
|
+
f"bestätigen (D-472, K-61)")
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
# --- Pruefung 61: Das Pruefmittelwort stammt aus dem Vokabular ----------------------
|
|
554
|
+
#
|
|
555
|
+
# ANLASS (D-181). Die dreizehn Testblaetter fuehrten bis 0.67.0 das Wort `manuell` -
|
|
556
|
+
# 87 von 87 Zellen. Im Vokabular von TEST_CATALOG.md Punkt 3 steht es nicht; es ist das
|
|
557
|
+
# ADJEKTIV aus der Definition von `sitzung` ("manuelle KI-Testsitzung nach Testblatt"),
|
|
558
|
+
# zum Methodennamen befoerdert. Jedes Blatt erklaerte es in seinem eigenen Vorspann -
|
|
559
|
+
# und damit war es fuer jeden Leser richtig und fuer jeden Zaehler unsichtbar.
|
|
560
|
+
#
|
|
561
|
+
# WAS DAS GEKOSTET HAT, IST GEMESSEN. Zwei Pruefungen laufen ausdruecklich ueber die
|
|
562
|
+
# dreizehn Blaetter und filtern auf `sitzung`: Pruefung 49 (D-146, seit 0.60.0) und
|
|
563
|
+
# Pruefung 60 (D-178, seit 0.66.0). Beide hatten dort NULL Gegenstand. Nach der
|
|
564
|
+
# Umstellung meldete Pruefung 60 beim ersten Lauf ZWANZIG Zellen - in genau den drei
|
|
565
|
+
# Blaettern, deren Skill einen Befehl ausfuehrt (fw-change-small, fw-refactor, fw-tests).
|
|
566
|
+
# Das ist die Bauform "Die Regel als Ausfuellschlitz" (0.61.0) eine Ebene hoeher: Nicht
|
|
567
|
+
# die Regel stand in zwei Ausdrucksformen, sondern ihr GEGENSTAND.
|
|
568
|
+
#
|
|
569
|
+
# GRENZE, UND SIE STEHT HIER. Geprueft wird das ERSTE WORT der Zelle gegen eine feste
|
|
570
|
+
# Menge. Ein Zusatz dahinter bleibt zulaessig - der zentrale Katalog fuehrt
|
|
571
|
+
# "sitzung + `validate-output.py`" und "skript+sitzung", die Blaetter
|
|
572
|
+
# "sitzung + Skript `validate-output.py --skill ...`". Nicht geprueft wird, ob das Wort
|
|
573
|
+
# das RICHTIGE ist; die Pruefung faengt ein fremdes Vokabular, nicht einen Irrtum.
|
|
574
|
+
P61_VOKABULAR = ("skript", "sitzung", "review")
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
def check_pruefmittel_vokabular(root: str) -> None:
|
|
578
|
+
"""Pruefung 61 (D-181): Das Pruefmittelwort stammt aus dem Vokabular des Katalogs."""
|
|
579
|
+
dateien = [os.path.join(root, KERN, "tests", "TEST_CATALOG.md")]
|
|
580
|
+
for basis in (os.path.join(root, KERN, "framework", "skills"),
|
|
581
|
+
os.path.join(root, KERN, "framework", "role-packs")):
|
|
582
|
+
for wurzel, _, files in os.walk(basis):
|
|
583
|
+
if "TESTS.md" in files:
|
|
584
|
+
dateien.append(os.path.join(wurzel, "TESTS.md"))
|
|
585
|
+
gesehen = 0
|
|
586
|
+
for pfad in sorted(dateien):
|
|
587
|
+
if not os.path.isfile(pfad):
|
|
588
|
+
continue
|
|
589
|
+
rel = os.path.relpath(pfad, root).replace(os.sep, "/")
|
|
590
|
+
i_pm = -1
|
|
591
|
+
for nr, zeile in enumerate(read(pfad).splitlines(), 1):
|
|
592
|
+
if not zeile.lstrip().startswith("|"):
|
|
593
|
+
continue
|
|
594
|
+
if "Prüfmethode" in zeile and "Eingabe" in zeile:
|
|
595
|
+
i_pm = _tabellenspalte(zeile, "Prüfmethode")
|
|
596
|
+
continue
|
|
597
|
+
if i_pm < 0:
|
|
598
|
+
continue
|
|
599
|
+
zellen = [z.strip() for z in zeile.strip().strip("|").split("|")]
|
|
600
|
+
if len(zellen) <= i_pm or not zellen[0]:
|
|
601
|
+
continue
|
|
602
|
+
if set(zellen[0]) <= set("-:"):
|
|
603
|
+
continue
|
|
604
|
+
wert = zellen[i_pm]
|
|
605
|
+
if not wert:
|
|
606
|
+
continue
|
|
607
|
+
gesehen += 1
|
|
608
|
+
# Das erste Wort, abgeschnitten an Leerzeichen und am Pluszeichen.
|
|
609
|
+
kopf = wert.split(" ")[0].split("+")[0].strip()
|
|
610
|
+
if kopf in P61_VOKABULAR:
|
|
611
|
+
continue
|
|
612
|
+
err(f"{rel}:{nr}: Prüfmittel '{kopf}' steht nicht im Vokabular "
|
|
613
|
+
f"({', '.join(P61_VOKABULAR)}). Zwei Prüfungen filtern auf `sitzung` und "
|
|
614
|
+
f"verlieren mit einem fremden Wort ihren Gegenstand, ohne es zu melden "
|
|
615
|
+
f"(D-146, D-178, D-181)")
|
|
616
|
+
if gesehen == 0:
|
|
617
|
+
err(f"{KERN}/tests/: keine Zelle mit Prüfmethode gefunden – Prüfung 61 hat ihren "
|
|
618
|
+
f"Gegenstand verloren; sie bestünde sonst leise (D-23)")
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
# --- Pruefung 62: die Version der Ausgabevorlage (D-185) ---------------------------
|
|
622
|
+
#
|
|
623
|
+
# ANLASS. Der erste Buendellauf der Testblaetter (0.68.0) hat elf Sitzungslaeufe
|
|
624
|
+
# gefahren; einer davon meldete in einer Nebenbemerkung, die Attributtabelle seines
|
|
625
|
+
# Skills nenne Version 0.1.3 und der Kopf der Ausgabevorlage v0.1.1 - er hat die
|
|
626
|
+
# hoehere genommen und es dazugeschrieben. Nachgezaehlt: 13 Traeger mit woertlicher
|
|
627
|
+
# Version, 10 davon abweichend, 15 Fundstellen.
|
|
628
|
+
#
|
|
629
|
+
# DER ZUSCHNITT IST DIE GANZE DATEI, nicht nur Abschnitt 5. Die zweite Fundstelle
|
|
630
|
+
# zweier Skills steht in der Zeile "| Erstellt mit | <skill> vX.Y.Z |" - derselbe
|
|
631
|
+
# Fehler an einer Stelle, die ein Zuschnitt auf die Ueberschrift verfehlt haette.
|
|
632
|
+
# Die Steckbriefzeile selbst traegt ihre Version OHNE das fuehrende `v` und faellt
|
|
633
|
+
# deshalb nicht unter das Muster; sie ist die Quelle, nicht die Kopie.
|
|
634
|
+
def check_skillversion_vorlage(root: str) -> None:
|
|
635
|
+
"""Pruefung 62 (D-185): Keine SKILL.md nennt eine Version woertlich."""
|
|
636
|
+
dateien = []
|
|
637
|
+
for basis in (os.path.join(root, KERN, "framework", "skills"),
|
|
638
|
+
os.path.join(root, KERN, "framework", "role-packs")):
|
|
639
|
+
for wurzel, _, files in os.walk(basis):
|
|
640
|
+
if "SKILL.md" in files:
|
|
641
|
+
dateien.append(os.path.join(wurzel, "SKILL.md"))
|
|
642
|
+
gesehen = 0
|
|
643
|
+
for pfad in sorted(dateien):
|
|
644
|
+
gesehen += 1
|
|
645
|
+
rel = os.path.relpath(pfad, root).replace(os.sep, "/")
|
|
646
|
+
text = read(pfad)
|
|
647
|
+
for nr, zeile in enumerate(text.splitlines(), 1):
|
|
648
|
+
for treffer in re.finditer(r"\bv\d+\.\d+\.\d+\b", zeile):
|
|
649
|
+
err(f"{rel}:{nr}: nennt die Version wörtlich ({treffer.group(0)}). Eine "
|
|
650
|
+
f"Zahl, die gepflegt werden muss, wird nicht gepflegt – gemessen "
|
|
651
|
+
f"waren zehn von dreizehn Trägern von ihrem eigenen Steckbrief "
|
|
652
|
+
f"abgewichen. Die Vorlage verweist auf den Steckbrief (D-185)")
|
|
653
|
+
if gesehen == 0:
|
|
654
|
+
err(f"{KERN}/framework/: keine SKILL.md gefunden – Prüfung 62 hat ihren "
|
|
655
|
+
f"Gegenstand verloren; sie bestünde sonst leise (D-23)")
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
# --- Pruefung 63: der Nummernverweis, der ins Leere zeigt (D-193) ------------------
|
|
659
|
+
#
|
|
660
|
+
# ANLASS. Der Vorbedingungsdurchgang von Buendel 2 (0.70.0) hat die achtzehn Zellen
|
|
661
|
+
# gegen den Bestand gehalten. Drei davon erwarten eine Bereinigung "nach
|
|
662
|
+
# 02-privacy.md Abschnitt 3.3" - und Abschnitt 3 jener Datei fuehrte zehn nummerierte
|
|
663
|
+
# REGELN und keine einzige Unterueberschrift. Nachgezaehlt gegen den unberuehrten
|
|
664
|
+
# Vorstand: 30 Verweise in 15 anweisenden Traegern auf vier Nummern (1.3, 3.3, 3.4,
|
|
665
|
+
# 3.5), die es als Abschnitt nicht gab.
|
|
666
|
+
#
|
|
667
|
+
# DIE FORM HATTE IN DERSELBEN DATEI ZWEI BEDEUTUNGEN. `Abschnitt 2.1` zeigte auf eine
|
|
668
|
+
# Ueberschrift, `Abschnitt 3.3` auf eine Listennummer, und 05-working-model.md fuehrt
|
|
669
|
+
# seine Querschnittsregeln laengst als `### 3.1` bis `### 3.6`. Das ZIELMODUL war der
|
|
670
|
+
# Ausreisser, nicht die dreissig Verweise: 0.70.0 hat die Ueberschriften nachgezogen
|
|
671
|
+
# und keinen der fuenfzehn Traeger angefasst. Eine Marke mit zwei Bedeutungen taugt
|
|
672
|
+
# weder als Bedingung noch als Entlastung.
|
|
673
|
+
#
|
|
674
|
+
# ZWEI AUSDRUCKSFORMEN, UND DIE ERSTE ZAEHLUNG KANNTE NUR EINE. Vier Testblaetter
|
|
675
|
+
# nennen das Ziel als blossen Dateinamen (`02-privacy.md`), nicht mit vollem Pfad -
|
|
676
|
+
# wer nur den vollen Pfad sucht, zaehlt 25 statt 30. Ein blosser Dateiname wird
|
|
677
|
+
# aufgeloest, wenn er im Kern GENAU EINMAL vorkommt; bei mehreren Treffern
|
|
678
|
+
# (README.md, TESTS.md, SKILL.md) wird nicht geraten.
|
|
679
|
+
#
|
|
680
|
+
# EINE bis-SPANNE IST MEHR ALS IHRE ENDEN. "Abschnitt 3.3 bis 3.5" nennt auch 3.4;
|
|
681
|
+
# wer nur die genannten Zahlen prueft, uebersieht die Mitte.
|
|
682
|
+
#
|
|
683
|
+
# AUFZEICHNUNGEN SIND AUSGENOMMEN (D-141), und die Liste dafuer ist keine neue:
|
|
684
|
+
# NEUTRAL_CHRONIK und NEUTRAL_FRIST. Ein Protokoll nennt den Stand seines Tages, und
|
|
685
|
+
# ein Aenderungsantrag den Gegenstand seines Eingriffs; beide nachtraeglich zu
|
|
686
|
+
# glaetten, zerstoerte die Nachvollziehbarkeit.
|
|
687
|
+
P63_VERWEIS = re.compile(
|
|
688
|
+
r"`(?P<pfad>[A-Za-z0-9_./-]*\.md)`[^`\n]{0,90}?Abschnitt\s+"
|
|
689
|
+
r"(?P<nummern>\d+(?:\.\d+)?(?:\s*(?:und|bis|,)\s*\d+(?:\.\d+)?)*)")
|
|
690
|
+
P63_UEBERSCHRIFT = re.compile(r"^#{2,6}\s+(\d+(?:\.\d+)*)\.?\s", re.M)
|
|
691
|
+
P63_AUSNAHMEN = NEUTRAL_CHRONIK + NEUTRAL_DOKUMENT
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
def _p63_nummern(roh: str) -> list:
|
|
695
|
+
"""Die genannten Nummern, bis-Spannen innerhalb desselben Abschnitts aufgeloest."""
|
|
696
|
+
teile = re.split(r"\s*(und|bis|,)\s*", roh)
|
|
697
|
+
werte, i = [teile[0]], 1
|
|
698
|
+
while i + 1 < len(teile):
|
|
699
|
+
verbinder, naechste = teile[i], teile[i + 1]
|
|
700
|
+
a, b = werte[-1].split("."), naechste.split(".")
|
|
701
|
+
if verbinder == "bis" and len(a) == 2 and len(b) == 2 and a[0] == b[0] \
|
|
702
|
+
and int(b[1]) > int(a[1]):
|
|
703
|
+
werte += ["%s.%d" % (a[0], k) for k in range(int(a[1]) + 1, int(b[1]) + 1)]
|
|
704
|
+
else:
|
|
705
|
+
werte.append(naechste)
|
|
706
|
+
i += 2
|
|
707
|
+
return werte
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
def check_nummernverweis(root: str) -> None:
|
|
711
|
+
"""Pruefung 63 (D-193): Ein Nummernverweis zeigt auf eine Ueberschrift des Ziels."""
|
|
712
|
+
kopf: dict = {}
|
|
713
|
+
nach_name: dict = {}
|
|
714
|
+
for path in iter_text_files(root):
|
|
715
|
+
if not path.endswith(".md"):
|
|
716
|
+
continue
|
|
717
|
+
rel = os.path.relpath(path, root).replace(os.sep, "/")
|
|
718
|
+
if not rel.startswith(KERN + "/"):
|
|
719
|
+
continue
|
|
720
|
+
nach_name.setdefault(os.path.basename(rel), []).append(rel)
|
|
721
|
+
kopf[rel] = {m.group(1) for m in P63_UEBERSCHRIFT.finditer(read(path))}
|
|
722
|
+
if not kopf:
|
|
723
|
+
err(f"{KERN}/: keine Markdown-Traeger gefunden - Pruefung 63 hat ihren "
|
|
724
|
+
f"Gegenstand verloren; sie bestuende sonst leise (D-23)")
|
|
725
|
+
return
|
|
726
|
+
for rel in sorted(kopf):
|
|
727
|
+
if rel.startswith(P63_AUSNAHMEN) or os.path.basename(rel) in NEUTRAL_CHRONIK_BASENAMES:
|
|
728
|
+
continue
|
|
729
|
+
pfad = os.path.join(root, rel.replace("/", os.sep))
|
|
730
|
+
for i, zeile in enumerate(read(pfad).splitlines(), 1):
|
|
731
|
+
for m in P63_VERWEIS.finditer(zeile):
|
|
732
|
+
genannt = m.group("pfad")
|
|
733
|
+
if genannt.startswith(KERN + "/"):
|
|
734
|
+
ziel = genannt if genannt in kopf else None
|
|
735
|
+
else:
|
|
736
|
+
kandidaten = nach_name.get(os.path.basename(genannt), [])
|
|
737
|
+
ziel = kandidaten[0] if len(kandidaten) == 1 else None
|
|
738
|
+
if ziel is None:
|
|
739
|
+
continue
|
|
740
|
+
for num in _p63_nummern(m.group("nummern")):
|
|
741
|
+
if num in kopf[ziel]:
|
|
742
|
+
continue
|
|
743
|
+
err(f"{rel}:{i}: verweist auf '{ziel}' Abschnitt {num} - diese "
|
|
744
|
+
f"Nummer fuehrt dort keine Ueberschrift. Ein Nummernverweis "
|
|
745
|
+
f"zeigt auf einen Abschnitt, nicht auf eine Listennummer; "
|
|
746
|
+
f"dieselbe Form bedeutete in 02-privacy.md einmal das eine und "
|
|
747
|
+
f"einmal das andere, und dreissig Verweise in fuenfzehn "
|
|
748
|
+
f"anweisenden Traegern zeigten ins Leere (D-193)")
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
# --- Pruefung 64: Die Ausgabemarke, die der Skill nicht verlangt --------------------
|
|
752
|
+
#
|
|
753
|
+
# ANLASS (D-197). `K-74` hat am 2026-09-19 gezaehlt, dass `[HALT]` und `[RUECKFRAGE]`
|
|
754
|
+
# mit 145 Fundstellen im Kern stehen und in keinem Glossar erklaert sind. Die
|
|
755
|
+
# Entscheidung dazu hat einen groesseren Befund freigelegt, und zwar durch eine
|
|
756
|
+
# Frage, die die Zaehlung nicht gestellt hatte: In WELCHEM Abschnitt steht die Marke?
|
|
757
|
+
#
|
|
758
|
+
# `[RUECKFRAGE]` steht in KEINEM Abschnitt 5 und in KEINEM Abschnitt 6 der
|
|
759
|
+
# zwoelf Skills. Sie ist durchgehend HANDLUNGSMARKE - "Fall X | [RUECKFRAGE]"
|
|
760
|
+
# heisst `frage zurueck`, nicht `schreibe die Zeichenfolge`.
|
|
761
|
+
#
|
|
762
|
+
# `[HALT]` ist beides, je nach Skill: Ausgabemarke in `fw-plan`, `fw-bugfix-prepare`
|
|
763
|
+
# und `fw-change-small` (Abschnitt 5 UND 6), Handlungsmarke in den uebrigen neun.
|
|
764
|
+
# Und wo sie Abnahmekriterium ist, sagt Abschnitt 6 "ist ERKENNBAR", nicht "woertlich".
|
|
765
|
+
#
|
|
766
|
+
# GEMESSEN HAT ES EIN LAUF. `sk004n01` (Buendel 2, 2026-09-19) schrieb `[HALT]`
|
|
767
|
+
# woertlich - Abschnitt 6 von `fw-plan` sagt "der Skill endet mit [HALT]" - und
|
|
768
|
+
# `[RUECKFRAGE]` nicht. Der Lauf hat sich richtig verhalten; die Zelle verlangte mehr,
|
|
769
|
+
# als ihr Skill vorschreibt. Ueber alle dreizehn Blaetter: 18 Nennungen in 17 Zellen
|
|
770
|
+
# ungedeckt, 10 gedeckt.
|
|
771
|
+
#
|
|
772
|
+
# GEGENSTAND. Nennt die Spalte "Erwartetes Verhalten" oder "Unzulaessiges Verhalten"
|
|
773
|
+
# einer Zelle eine Ausgabemarke, fuehrt der im Ausloeser aufgerufene Skill sie in
|
|
774
|
+
# Abschnitt 5 (Ausgabeformat) oder Abschnitt 6 (Qualitaetskriterien).
|
|
775
|
+
#
|
|
776
|
+
# WARUM ABSCHNITT 5 UND 6 UND NICHT 3 ODER 7. Abschnitt 3 (Arbeitsschritte) und
|
|
777
|
+
# Abschnitt 7 (Fehlerbehandlung) sagen, WAS ZU TUN IST; Abschnitt 5 und 6 sagen, WAS
|
|
778
|
+
# IN DER ANTWORT STEHEN MUSS. Ein Zuschnitt ueber die ganze Datei haette jede Zelle
|
|
779
|
+
# durchgelassen und nichts gemessen - die Marke steht ja irgendwo in jedem Skill.
|
|
780
|
+
# Das ist die Trennlinie von Pruefung 60 an einer zweiten Stelle: Dort sagt das
|
|
781
|
+
# FRONTMATTER, was der Skill tut, und der Fliesstext, wovon er redet.
|
|
782
|
+
#
|
|
783
|
+
# GRENZE, UND SIE STEHT HIER. Geprueft wird die DECKUNG, nicht die Formulierung.
|
|
784
|
+
# Eine Zelle, die die Sache umschreibt und dabei etwas Falsches sagt, laeuft durch.
|
|
785
|
+
# ZWEITE GRENZE: Die LETZTE Zelle einer Zeile ist der Ergebnisstatus und damit eine
|
|
786
|
+
# Aufzeichnung (D-117, D-141) - ein Lauf, der die Marke geschrieben HAT, darf das
|
|
787
|
+
# dort berichten. Dieselbe Spalten-Ausnahme, die Pruefung 48 zieht.
|
|
788
|
+
P64_MARKEN = {
|
|
789
|
+
"[HALT]": re.compile(r"\[HALT\]"),
|
|
790
|
+
"[RÜCKFRAGE]": re.compile(r"\[R(?:Ü|UE)CKFRAGE\]"),
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
def _p64_skillabschnitte(root: str) -> dict:
|
|
795
|
+
"""Skillname -> Menge der Marken, die Abschnitt 5 oder 6 seiner SKILL.md fuehrt.
|
|
796
|
+
|
|
797
|
+
Abgeleitet aus den Skillquellen, nicht gepflegt (dieselbe Regel wie bei
|
|
798
|
+
Pruefung 60 und 48): Wer eine Marke in ein Ausgabeformat aufnimmt, soll nicht
|
|
799
|
+
daran denken muessen, eine Liste im Validator nachzuziehen.
|
|
800
|
+
"""
|
|
801
|
+
raus = {}
|
|
802
|
+
for basis in (os.path.join(root, KERN, "framework", "skills"),
|
|
803
|
+
os.path.join(root, KERN, "framework", "role-packs")):
|
|
804
|
+
if not os.path.isdir(basis):
|
|
805
|
+
continue
|
|
806
|
+
for wurzel, _, files in os.walk(basis):
|
|
807
|
+
if "SKILL.md" not in files:
|
|
808
|
+
continue
|
|
809
|
+
text = read(os.path.join(wurzel, "SKILL.md")).replace("\r\n", "\n")
|
|
810
|
+
rumpf, aktuell = [], None
|
|
811
|
+
for zeile in text.split("\n"):
|
|
812
|
+
m = re.match(r"^##\s+(\d+)\.\s", zeile)
|
|
813
|
+
if m:
|
|
814
|
+
aktuell = int(m.group(1))
|
|
815
|
+
elif aktuell in (5, 6):
|
|
816
|
+
rumpf.append(zeile)
|
|
817
|
+
gefuehrt = {n for n, mu in P64_MARKEN.items() if mu.search("\n".join(rumpf))}
|
|
818
|
+
raus[os.path.basename(wurzel)] = gefuehrt
|
|
819
|
+
return raus
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
def check_ausgabemarke_gedeckt(root: str) -> None:
|
|
823
|
+
"""Pruefung 64 (D-197): Die Zelle verlangt nur, was ihr Skill als Ausgabe fuehrt."""
|
|
824
|
+
skills = _p64_skillabschnitte(root)
|
|
825
|
+
if not any(skills.values()):
|
|
826
|
+
err(f"{KERN}/framework/skills/: keine SKILL.md fuehrt eine Ausgabemarke in "
|
|
827
|
+
f"Abschnitt 5 oder 6 - Pruefung 64 leitet ihren Gegenstand daraus ab und "
|
|
828
|
+
f"hat ihn verloren; sie bestuende sonst leise (D-23)")
|
|
829
|
+
return
|
|
830
|
+
dateien = [os.path.join(root, KERN, "tests", "TEST_CATALOG.md")]
|
|
831
|
+
for basis in (os.path.join(root, KERN, "framework", "skills"),
|
|
832
|
+
os.path.join(root, KERN, "framework", "role-packs")):
|
|
833
|
+
for wurzel, _, files in os.walk(basis):
|
|
834
|
+
if "TESTS.md" in files:
|
|
835
|
+
dateien.append(os.path.join(wurzel, "TESTS.md"))
|
|
836
|
+
for pfad in sorted(dateien):
|
|
837
|
+
if not os.path.isfile(pfad):
|
|
838
|
+
continue
|
|
839
|
+
rel = os.path.relpath(pfad, root).replace(os.sep, "/")
|
|
840
|
+
i_ein = i_erw = i_unz = -1
|
|
841
|
+
for nr, zeile in enumerate(read(pfad).splitlines(), 1):
|
|
842
|
+
if not zeile.lstrip().startswith("|"):
|
|
843
|
+
continue
|
|
844
|
+
if "Erwartetes Verhalten" in zeile and "Eingabe" in zeile:
|
|
845
|
+
i_ein = _tabellenspalte(zeile, "Eingabe")
|
|
846
|
+
i_erw = _tabellenspalte(zeile, "Erwartetes Verhalten")
|
|
847
|
+
i_unz = _tabellenspalte(zeile, "Unzulässiges Verhalten")
|
|
848
|
+
continue
|
|
849
|
+
if min(i_ein, i_erw, i_unz) < 0:
|
|
850
|
+
continue
|
|
851
|
+
zellen = [z.strip() for z in zeile.strip().strip("|").split("|")]
|
|
852
|
+
if len(zellen) <= max(i_ein, i_erw, i_unz):
|
|
853
|
+
continue
|
|
854
|
+
# Die letzte Zelle ist der Ergebnisstatus - eine Aufzeichnung (D-117)
|
|
855
|
+
pruefbar = " ".join(z for i, z in enumerate(zellen)
|
|
856
|
+
if i in (i_erw, i_unz) and i != len(zellen) - 1)
|
|
857
|
+
gefuehrt = set()
|
|
858
|
+
for skill, marken in skills.items():
|
|
859
|
+
if f"/{skill}" in zellen[i_ein]:
|
|
860
|
+
gefuehrt |= marken
|
|
861
|
+
for name, muster in P64_MARKEN.items():
|
|
862
|
+
if muster.search(pruefbar) and name not in gefuehrt:
|
|
863
|
+
err(f"{rel}:{nr}: verlangt die Ausgabemarke {name}, die der "
|
|
864
|
+
f"aufgerufene Skill weder im Ausgabeformat (Abschnitt 5) noch "
|
|
865
|
+
f"in den Qualitaetskriterien (Abschnitt 6) fuehrt. Dort steht "
|
|
866
|
+
f"sie als Anweisung, nicht als Ausgabe - die Zelle verlangt "
|
|
867
|
+
f"damit mehr, als der Skill vorschreibt, und ein Lauf, der "
|
|
868
|
+
f"anhaelt ohne die Zeichenfolge zu schreiben, faellt zu "
|
|
869
|
+
f"Unrecht durch (D-197). Die Sache statt der Marke verlangen "
|
|
870
|
+
f"- oder die Marke in Abschnitt 5 beziehungsweise 6 aufnehmen")
|
|
871
|
+
|
|
872
|
+
# --- Pruefung 65: Der Ergebnisstatus ohne Beleg -------------------------------------
|
|
873
|
+
#
|
|
874
|
+
# ANLASS. TEST_CATALOG.md Punkt 4 sagt: "Ein Ergebnisstatus ausser `offen` MUSS auf ein
|
|
875
|
+
# Protokoll verweisen." D-117 sagt: "Ein Ergebnisstatus nennt das gemessene Client Pack
|
|
876
|
+
# und dessen Produktversion." Beides steht normativ da - und KEINE der vierundsechzig
|
|
877
|
+
# Pruefungen setzte es durch. Gezaehlt am 2026-09-19 ueber alle 125 Ergebniszellen des
|
|
878
|
+
# zentralen Katalogs und der dreizehn Testblaetter: NULL Verstoesse. Die Regel trug
|
|
879
|
+
# bisher allein durch die Sorgfalt derer, die sie eingetragen haben.
|
|
880
|
+
#
|
|
881
|
+
# WARUM SIE IN EINEM RELEASE GEBAUT WIRD, IN DEM SIE NICHTS FINDET. Dieses Release
|
|
882
|
+
# traegt in einem Zug ACHTZEHN neue `bestanden` ein - der Zeitpunkt, an dem eine
|
|
883
|
+
# ungezaehlte Belegpflicht rutscht. Die Bewegung ist die Umkehrung von Pruefung 60:
|
|
884
|
+
# Dort hatte eine Pruefung zwei Releases lang keinen Gegenstand und meldete dann zwanzig
|
|
885
|
+
# Zellen; hier ist der Gegenstand vollstaendig und soll es bleiben.
|
|
886
|
+
#
|
|
887
|
+
# DREI GEGENSTAENDE:
|
|
888
|
+
# (a) Das Statuswort stammt aus dem Vokabular von Punkt 4 - ABGELEITET aus jener
|
|
889
|
+
# Zeile, nicht gepflegt (dieselbe Regel wie bei Pruefung 61, 64 und 48).
|
|
890
|
+
# (b) Ein Status ausser `offen` nennt ein Protokoll unter tests/protocols/.
|
|
891
|
+
# (c) Ein Status ausser `offen` nennt bei Pruefmethode `sitzung` ein Client Pack mit
|
|
892
|
+
# Produktversion. Die Packkennungen kommen aus .koolie/core/clients/, nicht aus
|
|
893
|
+
# einer Handliste - ein neues Pack bringt seine Kennung selbst mit (D-117).
|
|
894
|
+
#
|
|
895
|
+
# WARUM (c) NUR BEI `sitzung`. D-117 spricht von DYNAMISCHEN Tests. Ein Validatorlauf
|
|
896
|
+
# (`skript`) misst das Repositorium und keinen Client, ein Dokumentenreview (`review`)
|
|
897
|
+
# ebenso; beide brauchen kein Pack. Der Zusatz hinter dem Wort bleibt zulaessig
|
|
898
|
+
# (`sitzung + validate-output.py`), deshalb wird auf ENTHALTENSEIN geprueft und nicht
|
|
899
|
+
# auf das erste Wort - `skript+sitzung` traegt beide Methoden und damit beide Pflichten.
|
|
900
|
+
#
|
|
901
|
+
# GRENZE, UND SIE STEHT HIER. Geprueft wird die NENNUNG, nicht ihre Richtigkeit: Ein
|
|
902
|
+
# Verweis auf ein Protokoll, das den Fall gar nicht behandelt, laeuft durch, und eine
|
|
903
|
+
# Version, die nicht die gemessene ist, ebenso. Das bleibt review-Gegenstand (D-23) -
|
|
904
|
+
# dieselbe Enthaltung, die Pruefung 61 fuer das RICHTIGE Pruefmittelwort zieht.
|
|
905
|
+
P65_MARKE = "**Ergebnisstatus:**"
|
|
906
|
+
P65_PROTOKOLL = re.compile(r"tests/protocols/[^\s`)]+\.md")
|
|
907
|
+
|
|
908
|
+
|
|
909
|
+
def _p65_vokabular(root: str) -> list:
|
|
910
|
+
"""Die zulaessigen Statuswoerter, abgeleitet aus TEST_CATALOG.md Punkt 4.
|
|
911
|
+
|
|
912
|
+
Nicht gepflegt: Wer das Vokabular dort erweitert, soll nicht daran denken muessen,
|
|
913
|
+
eine Liste im Validator nachzuziehen. Der Klammerzusatz ("(Referenz auf Befund)")
|
|
914
|
+
gehoert zur Erlaeuterung und nicht zum Wort.
|
|
915
|
+
"""
|
|
916
|
+
pfad = os.path.join(root, KERN, "tests", "TEST_CATALOG.md")
|
|
917
|
+
if not os.path.isfile(pfad):
|
|
918
|
+
return []
|
|
919
|
+
for zeile in read(pfad).splitlines():
|
|
920
|
+
if P65_MARKE not in zeile:
|
|
921
|
+
continue
|
|
922
|
+
rest = zeile.split(P65_MARKE, 1)[1]
|
|
923
|
+
m = re.match(r"\s*(`[^`]+`(?:\s*/\s*`[^`]+`)*)", rest)
|
|
924
|
+
if not m:
|
|
925
|
+
return []
|
|
926
|
+
return [t.strip("` ").split("(")[0].strip() for t in m.group(1).split("/")]
|
|
927
|
+
return []
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
def _p65_packkennungen(root: str) -> list:
|
|
931
|
+
"""Die Kennungen der Client Packs - aus dem Verzeichnis, nicht aus einer Liste."""
|
|
932
|
+
return [k for k, _d, _m in _client_packs(root)]
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
def check_ergebnisstatus_beleg(root: str) -> None:
|
|
936
|
+
"""Pruefung 65 (D-202): Ein Ergebnisstatus ausser `offen` traegt seinen Beleg."""
|
|
937
|
+
vokabular = _p65_vokabular(root)
|
|
938
|
+
if not vokabular:
|
|
939
|
+
err(f"{KERN}/tests/TEST_CATALOG.md: das Vokabular des Ergebnisstatus ist unter "
|
|
940
|
+
f"Punkt 4 nicht mehr auffindbar - Pruefung 65 leitet es von dort ab und hat "
|
|
941
|
+
f"ihren Gegenstand verloren; sie bestuende sonst leise (D-23)")
|
|
942
|
+
return
|
|
943
|
+
packs = _p65_packkennungen(root)
|
|
944
|
+
pack_re = re.compile("(" + "|".join(re.escape(k) for k in packs) +
|
|
945
|
+
r")[^|]{0,60}?\d+\.\d+\.\d+") if packs else None
|
|
946
|
+
dateien = [os.path.join(root, KERN, "tests", "TEST_CATALOG.md")]
|
|
947
|
+
for basis in (os.path.join(root, KERN, "framework", "skills"),
|
|
948
|
+
os.path.join(root, KERN, "framework", "role-packs")):
|
|
949
|
+
for wurzel, _, files in os.walk(basis):
|
|
950
|
+
if "TESTS.md" in files:
|
|
951
|
+
dateien.append(os.path.join(wurzel, "TESTS.md"))
|
|
952
|
+
gesehen = 0
|
|
953
|
+
for pfad in sorted(dateien):
|
|
954
|
+
if not os.path.isfile(pfad):
|
|
955
|
+
continue
|
|
956
|
+
rel = os.path.relpath(pfad, root).replace(os.sep, "/")
|
|
957
|
+
i_pm = i_st = -1
|
|
958
|
+
for nr, zeile in enumerate(read(pfad).splitlines(), 1):
|
|
959
|
+
if not zeile.lstrip().startswith("|"):
|
|
960
|
+
continue
|
|
961
|
+
if "Ergebnisstatus" in zeile and "Prüfmethode" in zeile:
|
|
962
|
+
i_pm = _tabellenspalte(zeile, "Prüfmethode")
|
|
963
|
+
i_st = _tabellenspalte(zeile, "Ergebnisstatus")
|
|
964
|
+
continue
|
|
965
|
+
if min(i_pm, i_st) < 0:
|
|
966
|
+
continue
|
|
967
|
+
zellen = [z.strip() for z in zeile.strip().strip("|").split("|")]
|
|
968
|
+
if len(zellen) <= max(i_pm, i_st) or not zellen[0]:
|
|
969
|
+
continue
|
|
970
|
+
if set(zellen[0]) <= set("-: "):
|
|
971
|
+
continue
|
|
972
|
+
# Die Betonung gehoert der Darstellung, nicht dem Wort.
|
|
973
|
+
status = zellen[i_st].lstrip("* ").strip()
|
|
974
|
+
if not status:
|
|
975
|
+
continue
|
|
976
|
+
gesehen += 1
|
|
977
|
+
wort = next((w for w in vokabular if status.startswith(w)), None)
|
|
978
|
+
if wort is None:
|
|
979
|
+
err(f"{rel}:{nr}: Ergebnisstatus beginnt nicht mit einem Wort des "
|
|
980
|
+
f"Vokabulars ({', '.join(vokabular)}) - TEST_CATALOG.md Punkt 4 "
|
|
981
|
+
f"fuehrt es abschliessend (D-202)")
|
|
982
|
+
continue
|
|
983
|
+
if wort == "offen":
|
|
984
|
+
continue
|
|
985
|
+
if not P65_PROTOKOLL.search(status):
|
|
986
|
+
err(f"{rel}:{nr}: Ergebnisstatus '{wort}' nennt kein Protokoll unter "
|
|
987
|
+
f"{KERN}/tests/protocols/. TEST_CATALOG.md Punkt 4: 'Ein "
|
|
988
|
+
f"Ergebnisstatus ausser offen MUSS auf ein Protokoll verweisen' - "
|
|
989
|
+
f"ohne den Verweis ist die Abnahme eine Behauptung (D-202)")
|
|
990
|
+
if pack_re is not None and "sitzung" in zellen[i_pm] \
|
|
991
|
+
and not pack_re.search(status):
|
|
992
|
+
err(f"{rel}:{nr}: Ergebnisstatus '{wort}' einer sitzung-Zelle nennt kein "
|
|
993
|
+
f"Client Pack mit Produktversion. Ein Ergebnisstatus deckt kein "
|
|
994
|
+
f"anderes Pack, und ohne die Version sagt er nicht, gegen welchen "
|
|
995
|
+
f"Produktstand gemessen wurde (D-117, D-202)")
|
|
996
|
+
if gesehen == 0:
|
|
997
|
+
err(f"{KERN}/tests/: keine Zelle mit Ergebnisstatus gefunden - Pruefung 65 hat "
|
|
998
|
+
f"ihren Gegenstand verloren; sie bestuende sonst leise (D-23)")
|
|
999
|
+
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
|
|
1003
|
+
# --- Pruefung 73: Jede [DOK]-Matrixzeile nennt ihre Quelle --------------------------
|
|
1004
|
+
#
|
|
1005
|
+
# ANLASS, UND ER IST GEZAEHLT (K-62, D-156, seit 0.62.0 offen, gemessen 2026-09-22).
|
|
1006
|
+
# Anhang 31.4 des Hauptdokuments sagt ueber sich selbst, die MASSGEBLICHE Zuordnung
|
|
1007
|
+
# stehe in der Faehigkeitsmatrix: "Dort nennt die Belegspalte je Zeile die Seite, auf
|
|
1008
|
+
# die sie sich stuetzt." Das traf am 2026-09-18 fuer 14 von 43 Zeilen zu - die Bauform
|
|
1009
|
+
# "eine Zusage, die mehr verspricht, als sie leistet", in ihrer Grundform.
|
|
1010
|
+
#
|
|
1011
|
+
# DER PREIS IST GEMESSEN, NICHT GESCHAETZT: Der Durchgang von FW-AK-01 musste ALLE 22
|
|
1012
|
+
# Quellen abrufen, weil ohne Zuordnung je Zeile nicht zu sagen ist, welche Seite welche
|
|
1013
|
+
# Zusage traegt. Eine Quellenliste ohne Zuordnung macht ihre eigene
|
|
1014
|
+
# Wiederholungspruefung so teuer wie die erste.
|
|
1015
|
+
#
|
|
1016
|
+
# DIE KOPFREGEL, UND SIE IST DER GRUND, WESHALB DIESE PRUEFUNG UEBERHAUPT ETWAS SAGT.
|
|
1017
|
+
# Geprueft wird der BELEGKOPF - die Zelle bis zum ersten Satzbruch (Punkt-Leerzeichen,
|
|
1018
|
+
# Semikolon, Doppelpunkt). Was danach steht, ist Erlaeuterung. Ohne diese Trennung
|
|
1019
|
+
# zaehlte jede Nennung der Marke mit: Zeile R5 des Packs claude-code erklaert, "ein
|
|
1020
|
+
# Dokumentenabgleich belegt [DOK], nicht [TECHNISCH]" - das ist eine Aussage UEBER die
|
|
1021
|
+
# Marke und kein Beleg. Dieselbe Trennlinie, die der VERIFY-Marker am Ende braucht
|
|
1022
|
+
# (CR-2026-070 E3): die nur nennende Fundstelle zaehlt nicht wie die tragende.
|
|
1023
|
+
#
|
|
1024
|
+
# WARUM DIE KENNUNG UND NICHT DER SEITENPFAD. Das Pack devin-desktop nannte QD-6, das
|
|
1025
|
+
# Pack claude-code `docs/en/memory` - dieselbe Sache in zwei Schreibweisen. Nur die
|
|
1026
|
+
# Kennung laesst sich gegen die Liste halten; ein Pfad kann eine Seite nennen, die die
|
|
1027
|
+
# Liste gar nicht fuehrt, und dann behauptet die Liste wieder mehr, als sie leistet.
|
|
1028
|
+
# Der Pfad darf danebenstehen, er ist Lesehilfe.
|
|
1029
|
+
#
|
|
1030
|
+
# WARUM DER VERWEIS AUFGELOEST WIRD. Vier Zeilen des Packs devin-desktop belegen mit
|
|
1031
|
+
# "wie B3", eine davon ueber zwei Glieder ("wie B4" -> "wie B3"). Solange B3 keine
|
|
1032
|
+
# Kennung trug, trugen FUENF Zeilen keine - und keine Zaehlung, die den Verweis nicht
|
|
1033
|
+
# aufloest, sieht das. Die Zusammenfassung des Packs zaehlt sie umgekehrt sehr wohl mit
|
|
1034
|
+
# ("neun der 36 Zeilen tragen einen offenen VERIFY-Marker - ... B4, B5, B6 und B8 ueber
|
|
1035
|
+
# den Verweis"): Wer sie beim Marker mitzaehlt und beim Beleg nicht, hat zwei
|
|
1036
|
+
# Zaehlregeln fuer dieselbe Spalte.
|
|
1037
|
+
#
|
|
1038
|
+
# WARUM EINE AUSGESPROCHENE LUECKE ZULAESSIG IST UND TROTZDEM NICHT WACHSEN KANN.
|
|
1039
|
+
# D-156 sagt: "Eine Zuordnung zu raten waere schlimmer als keine: Sie saehe wie ein
|
|
1040
|
+
# Beleg aus." Fuer Zeile M3 des Packs claude-code gibt der Bestand keine Seite her -
|
|
1041
|
+
# keine der sechs Seiten fuehrt die Sitzungs-Grant-Stufen, waehrend sie beim
|
|
1042
|
+
# Schwesterpack in QD-11 stehen. Die Zeile sagt das mit der Marke
|
|
1043
|
+
# QUELLE NICHT ZUGEORDNET. Damit das keine Hintertuer ist, fuehrt diese Pruefung die
|
|
1044
|
+
# zugelassenen Luecken als MENGE: eine neue faellt auf, und eine geschlossene ebenso -
|
|
1045
|
+
# dieselbe Bauform wie das leer DEKLARIERTE Feld von Pruefung 72 (D-155).
|
|
1046
|
+
P73_KENNUNG_RE = re.compile(r"Q[CDKU]-\d+") # QK- seit 1.13.0 (kiro, D-414), QU- seit 1.16.0 (cursor, D-440)
|
|
1047
|
+
P73_BRUCH_RE = re.compile(r"\.\s|;\s|:\s|:$")
|
|
1048
|
+
P73_VERWEIS_RE = re.compile(r"^(?:wie|dito)\b[^A-Z]*([RSBHAMX]\d+)")
|
|
1049
|
+
P73_OFFEN_MARKE = "QUELLE NICHT ZUGEORDNET"
|
|
1050
|
+
# Die ausgesprochenen Luecken, je Pack. Wer eine neue braucht, traegt sie hier ein -
|
|
1051
|
+
# und begruendet sie im Aenderungsantrag. Wer eine schliesst, nimmt sie hier heraus.
|
|
1052
|
+
P73_OFFEN = {"claude-code": {"M3"}}
|
|
1053
|
+
P73_SELBSTPROBE = ("`[DOK]` **`QC-9`** (synthetisch)", "`[DOK]` ohne Kennung")
|
|
1054
|
+
|
|
1055
|
+
|
|
1056
|
+
def _p73_kopf(zelle: str) -> str:
|
|
1057
|
+
"""Der Belegkopf: die Zelle bis zum ersten Satzbruch."""
|
|
1058
|
+
m = P73_BRUCH_RE.search(zelle)
|
|
1059
|
+
return zelle[:m.start() + 1] if m else zelle
|
|
1060
|
+
|
|
1061
|
+
|
|
1062
|
+
def _p73_matrixzeilen(root: str, pack: str) -> dict:
|
|
1063
|
+
"""{Kennung: Belegzelle} der Faehigkeitsmatrix eines Packs, in Lesereihenfolge."""
|
|
1064
|
+
pfad = os.path.join(root, KERN, "clients", pack, "CLIENT_PACK.md")
|
|
1065
|
+
if not os.path.isfile(pfad):
|
|
1066
|
+
return {}
|
|
1067
|
+
aus = {}
|
|
1068
|
+
drin = False
|
|
1069
|
+
for zeile in read(pfad).replace("\r\n", "\n").split("\n"):
|
|
1070
|
+
if zeile.startswith("## 2. "):
|
|
1071
|
+
drin = True
|
|
1072
|
+
continue
|
|
1073
|
+
if drin and re.match(r"^## \d", zeile):
|
|
1074
|
+
drin = False
|
|
1075
|
+
if not drin:
|
|
1076
|
+
continue
|
|
1077
|
+
m = P73_ZEILE_RE.match(zeile)
|
|
1078
|
+
if not m:
|
|
1079
|
+
continue
|
|
1080
|
+
zellen = tabellenzellen(zeile)
|
|
1081
|
+
if zellen:
|
|
1082
|
+
aus[m.group(1)] = zellen[-1]
|
|
1083
|
+
return aus
|
|
1084
|
+
|
|
1085
|
+
|
|
1086
|
+
def _p73_aufgeloest(zellen: dict, kennung: str) -> tuple:
|
|
1087
|
+
"""Der Belegkopf einer Zeile, Verweise aufgeloest. (Kopf, Kette)."""
|
|
1088
|
+
ziel, kette = kennung, []
|
|
1089
|
+
for _ in range(5):
|
|
1090
|
+
kopf = _p73_kopf(zellen[ziel])
|
|
1091
|
+
m = P73_VERWEIS_RE.match(kopf)
|
|
1092
|
+
if not m or m.group(1) not in zellen or m.group(1) in kette:
|
|
1093
|
+
return kopf, kette
|
|
1094
|
+
kette.append(m.group(1))
|
|
1095
|
+
ziel = m.group(1)
|
|
1096
|
+
err(f"Faehigkeitsmatrix, Zeile {ziel}: der Belegverweis laeuft ueber mehr als "
|
|
1097
|
+
f"fuenf Glieder. Eine Belegkette, die niemand bis zum Ende liest, ist kein "
|
|
1098
|
+
f"Beleg (D-266)")
|
|
1099
|
+
return "", kette
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
def check_belegquelle(root: str) -> None:
|
|
1103
|
+
"""Pruefung 73 (D-263): Jede `[DOK]`-Matrixzeile nennt ihre Quellenkennung."""
|
|
1104
|
+
gut, schlecht = P73_SELBSTPROBE
|
|
1105
|
+
if not P73_KENNUNG_RE.search(_p73_kopf(gut)) or P73_KENNUNG_RE.search(_p73_kopf(schlecht)):
|
|
1106
|
+
err("Pruefung 73: die eigene Selbstprobe traegt nicht mehr - die Pruefung "
|
|
1107
|
+
"haette ihren Gegenstand verloren und bestuende leise (D-23)")
|
|
1108
|
+
return
|
|
1109
|
+
verz = os.path.join(root, KERN, "clients")
|
|
1110
|
+
if not os.path.isdir(verz):
|
|
1111
|
+
err(f"{KERN}/clients/ fehlt - Pruefung 73 haette keinen Gegenstand (D-23)")
|
|
1112
|
+
return
|
|
1113
|
+
packs = sorted(n for n in os.listdir(verz)
|
|
1114
|
+
if n != "_template"
|
|
1115
|
+
and os.path.isfile(os.path.join(verz, n, "CLIENT_PACK.md")))
|
|
1116
|
+
if not packs:
|
|
1117
|
+
err(f"{KERN}/clients/: kein Client Pack mit CLIENT_PACK.md gefunden - "
|
|
1118
|
+
f"Pruefung 73 haette keinen Gegenstand (D-23)")
|
|
1119
|
+
return
|
|
1120
|
+
for pack in packs:
|
|
1121
|
+
zellen = _p73_matrixzeilen(root, pack)
|
|
1122
|
+
if not zellen:
|
|
1123
|
+
err(f"clients/{pack}/CLIENT_PACK.md: unter '## 2.' steht keine "
|
|
1124
|
+
f"Matrixzeile. Pruefung 73 liest die Faehigkeitsmatrix dort und "
|
|
1125
|
+
f"haette ohne sie nichts zu pruefen (D-23)")
|
|
1126
|
+
continue
|
|
1127
|
+
erwartet = set(P73_OFFEN.get(pack, ()))
|
|
1128
|
+
gefunden = set()
|
|
1129
|
+
for kennung in zellen:
|
|
1130
|
+
kopf, kette = _p73_aufgeloest(zellen, kennung)
|
|
1131
|
+
if "[DOK]" not in kopf:
|
|
1132
|
+
continue
|
|
1133
|
+
ueber = f" (ueber den Verweis {' → '.join(kette)})" if kette else ""
|
|
1134
|
+
if P73_OFFEN_MARKE in kopf:
|
|
1135
|
+
gefunden.add(kette[-1] if kette else kennung)
|
|
1136
|
+
continue
|
|
1137
|
+
if not P73_KENNUNG_RE.search(kopf):
|
|
1138
|
+
err(f"clients/{pack}/CLIENT_PACK.md: Zeile {kennung} ist mit `[DOK]` "
|
|
1139
|
+
f"belegt und nennt im Belegkopf keine Quellenkennung "
|
|
1140
|
+
f"(`QC-n`/`QD-n`){ueber}. Anhang 31.4 sagt zu, die Zuordnung "
|
|
1141
|
+
f"stehe je Zeile in der Matrix; eine Zeile ohne sie macht jede "
|
|
1142
|
+
f"Wiederholung von `FW-AK-01` so teuer wie die erste (K-62, "
|
|
1143
|
+
f"D-156). Gibt der Bestand keine Seite her, sagt die Zeile "
|
|
1144
|
+
f"`{P73_OFFEN_MARKE}` - geraten wird nicht, eine geratene "
|
|
1145
|
+
f"Zuordnung saehe wie ein Beleg aus (D-263)")
|
|
1146
|
+
for offen in sorted(gefunden - erwartet):
|
|
1147
|
+
err(f"clients/{pack}/CLIENT_PACK.md: Zeile {offen} sagt "
|
|
1148
|
+
f"`{P73_OFFEN_MARKE}`, steht aber nicht in P73_OFFEN. Eine "
|
|
1149
|
+
f"ausgesprochene Luecke ist zulaessig und wird DEKLARIERT - sonst "
|
|
1150
|
+
f"waere sie eine Hintertuer, durch die die Zusage von Anhang 31.4 "
|
|
1151
|
+
f"still wieder kleiner wird (D-263)")
|
|
1152
|
+
for offen in sorted(erwartet - gefunden):
|
|
1153
|
+
err(f"clients/{pack}/CLIENT_PACK.md: P73_OFFEN fuehrt Zeile {offen} als "
|
|
1154
|
+
f"ausgesprochene Luecke, die Zeile sagt es aber nicht (mehr). Ist die "
|
|
1155
|
+
f"Quelle nachgetragen, gehoert der Eintrag heraus; eine Ausnahme ohne "
|
|
1156
|
+
f"Gegenstand sieht wie Sorgfalt aus und ist tot (0.57.1, D-263)")
|
|
1157
|
+
|
|
1158
|
+
|
|
1159
|
+
# ---------------------------------------------------------------------------
|
|
1160
|
+
# PRUEFUNG 95: DER AENDERUNGSVERLAUF EINES SKILLS NENNT DIE ART (CR-2026-147, D-403)
|
|
1161
|
+
# ---------------------------------------------------------------------------
|
|
1162
|
+
#
|
|
1163
|
+
# ANLASS. D-303 oeffnet die Zellen eines Testblatts nur, wenn eine Aenderung eine
|
|
1164
|
+
# ANWEISUNG des Skills beruehrt - und die Grenze zieht ein Mensch. Seit D-303 nennt jede
|
|
1165
|
+
# neue Zeile eines Skill-Aenderungsverlaufs diese Einordnung ("Keine Anweisung beruehrt"
|
|
1166
|
+
# oder "Anweisung beruehrt"), aber keine Pruefung sah, ob sie dasteht (K-146).
|
|
1167
|
+
# GEGENSTAND: die Zeile der Version, die der Steckbrief der SKILL.md nennt, und jede
|
|
1168
|
+
# Zeile mit einem Datum nach dem Stichtag. Aeltere Zeilen bleiben, wie sie geschrieben
|
|
1169
|
+
# wurden (Klasse C). NUR DIE SKILLS DES KERNS: D-303 regelt die Testblaetter des
|
|
1170
|
+
# Frameworks; ein projekteigener Skill fuehrt seinen Verlauf nach eigener Regel. Beim
|
|
1171
|
+
# ersten Heben mit dieser Pruefung meldete sie im Uebungsrepositorium die Erstfassung
|
|
1172
|
+
# eines prj-Skills. Die installierten Kopien der Kernskills sind Kopien der Quelle,
|
|
1173
|
+
# die hier geprueft wird.
|
|
1174
|
+
# GRENZE: Die Pruefung sieht die NENNUNG, nicht ihre Richtigkeit. Ob eine Aenderung eine
|
|
1175
|
+
# Anweisung beruehrt, entscheidet weiter ein Mensch (Preis von D-303, benannt).
|
|
1176
|
+
P95_STICHTAG = "2026-09-22"
|
|
1177
|
+
P95_ART_RE = re.compile(r"Anweisung\s+ber(?:ü|ue)hrt", re.I)
|
|
1178
|
+
P95_ZEILE_RE = re.compile(r"^\|\s*(\d+\.\d+\.\d+)\s*\|\s*(\d{4}-\d\d-\d\d)\s*\|", re.M)
|
|
1179
|
+
|
|
1180
|
+
|
|
1181
|
+
def check_skill_aenderungsart(root: str, man: dict) -> None:
|
|
1182
|
+
"""Pruefung 95 (D-403): der Aenderungsverlauf eines Skills nennt die Art der Aenderung."""
|
|
1183
|
+
for skills_dir, prefix in skill_dirs(root, man):
|
|
1184
|
+
if not prefix.startswith(KERN + "/"):
|
|
1185
|
+
continue
|
|
1186
|
+
for name in sorted(os.listdir(skills_dir)):
|
|
1187
|
+
sdir = os.path.join(skills_dir, name)
|
|
1188
|
+
skill_path = os.path.join(sdir, "SKILL.md")
|
|
1189
|
+
cl_path = os.path.join(sdir, "CHANGELOG.md")
|
|
1190
|
+
if not (os.path.exists(skill_path) and os.path.exists(cl_path)):
|
|
1191
|
+
continue
|
|
1192
|
+
m = re.search(r"^\|\s*Version\s*\|\s*`?([^`|]+?)`?\s*\|", read(skill_path), re.M)
|
|
1193
|
+
aktuell = m.group(1).strip() if m else None
|
|
1194
|
+
for zeile in read(cl_path).splitlines():
|
|
1195
|
+
z = P95_ZEILE_RE.match(zeile)
|
|
1196
|
+
if not z or not (z.group(1) == aktuell or z.group(2) > P95_STICHTAG):
|
|
1197
|
+
continue
|
|
1198
|
+
if not P95_ART_RE.search(zeile):
|
|
1199
|
+
err(f"{prefix}/{name}/CHANGELOG.md: die Zeile {z.group(1)} nennt nicht, "
|
|
1200
|
+
f"ob sie eine Anweisung berührt ('Keine Anweisung berührt' oder "
|
|
1201
|
+
f"'Anweisung berührt') – davon hängt ab, ob die Zellen des "
|
|
1202
|
+
f"Testblatts offen sind (D-303, D-403)")
|