@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,1251 @@
|
|
|
1
|
+
"""Das Project Overlay: aktiver Zustand, Aktivierungsreife, ausgeschlossene Pfade,
|
|
2
|
+
Schlitze, Freigabefolge, Pflichtplatzhalter, Platzhalterbindung, Vorbedingungen,
|
|
3
|
+
Befehlsschlitz, Wert- und Pfadabgleich.
|
|
4
|
+
|
|
5
|
+
Pruefungen 9, 9a, 28, 51, 52, 55a, 55b, 56, 57, 59, 60, 89, 110 und 111. 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 json
|
|
12
|
+
import os
|
|
13
|
+
import re
|
|
14
|
+
|
|
15
|
+
from overlay_status import (
|
|
16
|
+
AKTIV, auswerten, INAKTIV, status_angaben, UNBEKANNT, WIDERSPRUECHLICH)
|
|
17
|
+
|
|
18
|
+
from .gemeinsam import (
|
|
19
|
+
_tabellenspalte, _ueb_katalogdateien, err, formatgebunden, KERN, PLACEHOLDER_RE,
|
|
20
|
+
fremde_praefixe,
|
|
21
|
+
PROJEKTPLATZHALTER, read, regeldatei, tabellenzellen, TBD_RE, warn)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Abschnitte des Overlays, die ueber die Aktivierungsreife entscheiden. Sie muessen da
|
|
25
|
+
# sein und sie muessen ausgefuellt sein - das eine ohne das andere ist keine Pruefung.
|
|
26
|
+
SICHERHEITSABSCHNITTE = ("## 4.", "## 5.", "## 6.", "## 13.", "## 14.", "## 15.")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def check_strict_overlay(root: str, man: dict) -> None:
|
|
30
|
+
"""Der **aktive** Zustand des Projekts (--strict-overlay) - clientneutral.
|
|
31
|
+
|
|
32
|
+
Diese Funktion hiess bis 0.32.0 im Docstring und im Uebernahmeleitfaden "Pruefung der
|
|
33
|
+
Aktivierungsreife" und verlangte dabei den Status 'aktiv'. Das war der Kern von B08:
|
|
34
|
+
Der Leitfaden fuhr sie in Schritt 7 und setzte 'aktiv' erst in Schritt 9, die
|
|
35
|
+
Uebernahmecheckliste trug sie als MUSS und galt "vor dem Setzen auf aktiv" - eine
|
|
36
|
+
Voraussetzung, die sich selbst verlangte. Die Reifepruefung heisst seit 0.33.0
|
|
37
|
+
--check-overlay-ready und ist eine eigene Funktion (D-57). Diese hier prueft den
|
|
38
|
+
fertigen Zustand und bleibt dafuer unveraendert; sie hat mit dem
|
|
39
|
+
Aktualisierungsablauf einen zweiten, funktionierenden Aufrufer.
|
|
40
|
+
|
|
41
|
+
Bis 0.27.0 las diese Funktion zwei fest verdrahtete Pfade **eines** Clients und bekam
|
|
42
|
+
das erkannte Manifest nicht uebergeben. In einer Installation des anderen Packs fand
|
|
43
|
+
sie nichts, uebersprang alles und meldete null zusaetzliche Fehler.
|
|
44
|
+
|
|
45
|
+
Gemessen am 2026-09-12 an zwei frischen Installationen mit demselben Defekt: Beim
|
|
46
|
+
einen Pack aenderte sich die Fehlerzahl, beim anderen nicht (B02, D-44). Die
|
|
47
|
+
Clienterkennung steht seit der Umstellung auf mehrere Packs in derselben Datei; sie
|
|
48
|
+
wurde hier nur nicht benutzt.
|
|
49
|
+
|
|
50
|
+
Zwei Befunde derselben Funktion sind dabei mit erledigt, beide aus der Messung:
|
|
51
|
+
|
|
52
|
+
* **Der Status wurde als Praefix geprueft.** Damit bestand 'aktivierung-ausstehend'
|
|
53
|
+
die Aktivierungspruefung - ein Wert, der woertlich sagt, dass die Aktivierung
|
|
54
|
+
aussteht, liess den Fehler verschwinden, der vorher stand. Wer ihn eintrug, machte
|
|
55
|
+
die Pruefung stiller. Jetzt gilt genau 'aktiv'.
|
|
56
|
+
* **Ein fehlender sicherheitsrelevanter Abschnitt wurde akzeptiert.** Die Pruefung
|
|
57
|
+
suchte nur in vorhandenen Abschnitten nach offenen Werten; fehlte der Abschnitt,
|
|
58
|
+
fand sie nichts. Ein Overlay ohne Abschnitt 13 stand damit besser da als eines mit
|
|
59
|
+
einem offenen Wert darin - die Pruefung auf den Kopf gestellt.
|
|
60
|
+
|
|
61
|
+
GRENZE: Geprueft wird die Aktivierungs**reife**, nicht die Aktivierung. Dass ein
|
|
62
|
+
Overlay 'aktiv' sagt, heisst nicht, dass der Client seine Regeln laedt.
|
|
63
|
+
"""
|
|
64
|
+
runtime = os.path.join(root, *man["pack_runtime_dir"].split("/"), regeldatei(man, "20-project-overlay.md"))
|
|
65
|
+
overlay = os.path.join(root, ".koolie/project-overlay", "OVERLAY.md")
|
|
66
|
+
for path in (runtime, overlay):
|
|
67
|
+
if not os.path.exists(path):
|
|
68
|
+
continue
|
|
69
|
+
text = read(path)
|
|
70
|
+
rel = os.path.relpath(path, root).replace(os.sep, "/")
|
|
71
|
+
angaben = status_angaben(text)
|
|
72
|
+
status, grund = auswerten(angaben)
|
|
73
|
+
if status != AKTIV:
|
|
74
|
+
# Der **Rohwert** gehoert in die Meldung, nicht nur die Auswertung: Der Fall,
|
|
75
|
+
# der D-44 ausgeloest hat, war der Wert 'aktivierung-ausstehend' - er sagt
|
|
76
|
+
# woertlich, dass die Aktivierung aussteht, und genau das soll lesbar sein.
|
|
77
|
+
# Die Sonde zu D-44 hat diesen Verlust beim Umbau auf overlay_status.py
|
|
78
|
+
# gefangen; ohne sie waere die Meldung stiller geworden.
|
|
79
|
+
roh = ", ".join("'%s'" % a.strip() for a in angaben) or "keine Angabe"
|
|
80
|
+
err(f"{rel}: Overlay-Status ist nicht '{AKTIV}', sondern {roh} "
|
|
81
|
+
f"(ausgewertet als '{status}': {grund}) (strict-overlay)")
|
|
82
|
+
if path == runtime and TBD_RE.search(text):
|
|
83
|
+
err(f"{rel}: enthält offene <TBD>-Werte (strict-overlay)")
|
|
84
|
+
if path == overlay:
|
|
85
|
+
for sec in SICHERHEITSABSCHNITTE:
|
|
86
|
+
m = re.search(rf"{re.escape(sec)}.*?(?=\n## |\Z)", text, re.S)
|
|
87
|
+
if not m:
|
|
88
|
+
err(f"{rel}: sicherheitsrelevanter Abschnitt {sec} fehlt (strict-overlay)")
|
|
89
|
+
elif TBD_RE.search(m.group(0)):
|
|
90
|
+
err(f"{rel}: Abschnitt {sec} enthält offene <TBD>-Werte (sicherheitsrelevant, strict-overlay)")
|
|
91
|
+
rechte = os.path.join(root, *man["permissions_file"].split("/"))
|
|
92
|
+
if os.path.exists(rechte):
|
|
93
|
+
inhalt = read(rechte)
|
|
94
|
+
if TBD_RE.search(inhalt) or PLACEHOLDER_RE.search(inhalt):
|
|
95
|
+
err(f"{man['permissions_file']}: enthält noch Platzhalter (strict-overlay)")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def check_overlay_ready(root: str, man: dict) -> None:
|
|
99
|
+
"""Aktivierungsreife eines Kandidaten (--check-overlay-ready) - clientneutral.
|
|
100
|
+
|
|
101
|
+
Die Pruefung, die B08 gefehlt hat: Sie prueft alles, was --strict-overlay prueft,
|
|
102
|
+
**ausser** dem Status - und beim Status erwartet sie das Gegenteil, naemlich einen
|
|
103
|
+
Kandidaten, der noch nicht aktiv ist. Damit ist der dokumentierte Ablauf ohne
|
|
104
|
+
Regelbruch begehbar: erst vollstaendig ausfuellen und pruefen, dann durch einen
|
|
105
|
+
Menschen aktivieren, dann mit --strict-overlay nachpruefen (D-57).
|
|
106
|
+
|
|
107
|
+
Warum sie einen aktiven Kandidaten als Fehler meldet und nicht durchlaesst: Sonst
|
|
108
|
+
waere sie die schwaechere Variante von --strict-overlay und wuerde als deren Ersatz
|
|
109
|
+
benutzt. Eine Pruefung, die zwei Zustaende gleich behandelt, unterscheidet keine zwei
|
|
110
|
+
Zustaende.
|
|
111
|
+
|
|
112
|
+
Die Statusangaben MUESSEN untereinander uebereinstimmen. Ein Kandidat, der in der
|
|
113
|
+
Laufzeitfassung 'aktiv' und im Quell-Overlay 'inaktiv' erklaert, ist kein Kandidat,
|
|
114
|
+
sondern eine Drift - derselbe Fall, den der Status-Hook bis 0.32.0 zugunsten der
|
|
115
|
+
ersten gelesenen Datei entschied.
|
|
116
|
+
|
|
117
|
+
GRENZE: Geprueft wird die Vollstaendigkeit der Konfiguration. Die **fachliche**
|
|
118
|
+
Freigabe kann kein Skript erteilen; die Uebernahmecheckliste bleibt der Nachweis
|
|
119
|
+
(FW-CL-10). Und dass ein Overlay vollstaendig ist, heisst nicht, dass seine Werte
|
|
120
|
+
richtig sind.
|
|
121
|
+
"""
|
|
122
|
+
runtime = os.path.join(root, *man["pack_runtime_dir"].split("/"), regeldatei(man, "20-project-overlay.md"))
|
|
123
|
+
overlay = os.path.join(root, ".koolie/project-overlay", "OVERLAY.md")
|
|
124
|
+
vorhanden = [p for p in (runtime, overlay) if os.path.exists(p)]
|
|
125
|
+
if not vorhanden:
|
|
126
|
+
err("check-overlay-ready: weder die Laufzeitfassung des Overlays noch "
|
|
127
|
+
".koolie/project-overlay/OVERLAY.md ist vorhanden - es gibt keinen Kandidaten")
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
alle_angaben = []
|
|
131
|
+
for path in vorhanden:
|
|
132
|
+
text = read(path)
|
|
133
|
+
rel = os.path.relpath(path, root).replace(os.sep, "/")
|
|
134
|
+
angaben = status_angaben(text)
|
|
135
|
+
alle_angaben.extend(angaben)
|
|
136
|
+
if not angaben:
|
|
137
|
+
err(f"{rel}: keine Angabe zum Overlay-Status gefunden (check-overlay-ready)")
|
|
138
|
+
# Offene Werte: in der Laufzeitfassung ueberall, im Overlay in den
|
|
139
|
+
# sicherheitsrelevanten Abschnitten. Dieselbe Aufteilung wie --strict-overlay;
|
|
140
|
+
# ein Kandidat unterscheidet sich vom aktiven Overlay im Status, nicht im Inhalt.
|
|
141
|
+
if path == runtime and TBD_RE.search(text):
|
|
142
|
+
err(f"{rel}: enthält offene <TBD>-Werte (check-overlay-ready)")
|
|
143
|
+
if path == overlay:
|
|
144
|
+
for sec in SICHERHEITSABSCHNITTE:
|
|
145
|
+
m = re.search(rf"{re.escape(sec)}.*?(?=\n## |\Z)", text, re.S)
|
|
146
|
+
if not m:
|
|
147
|
+
err(f"{rel}: sicherheitsrelevanter Abschnitt {sec} fehlt "
|
|
148
|
+
f"(check-overlay-ready)")
|
|
149
|
+
elif TBD_RE.search(m.group(0)):
|
|
150
|
+
err(f"{rel}: Abschnitt {sec} enthält offene <TBD>-Werte "
|
|
151
|
+
f"(sicherheitsrelevant, check-overlay-ready)")
|
|
152
|
+
|
|
153
|
+
status, grund = auswerten(alle_angaben)
|
|
154
|
+
if status == AKTIV:
|
|
155
|
+
err(f"check-overlay-ready: Der Overlay-Status ist bereits '{AKTIV}'. Diese "
|
|
156
|
+
f"Pruefung gilt fuer einen Kandidaten **vor** der Aktivierung; fuer den "
|
|
157
|
+
f"aktiven Zustand ist --strict-overlay zustaendig (D-57)")
|
|
158
|
+
elif status == WIDERSPRUECHLICH:
|
|
159
|
+
err(f"check-overlay-ready: {grund}. Ein Kandidat erklaert seinen Status an allen "
|
|
160
|
+
f"Stellen gleich; abweichende Angaben sind eine Drift, kein Kandidat")
|
|
161
|
+
elif status == UNBEKANNT:
|
|
162
|
+
err(f"check-overlay-ready: Overlay-Status nicht ausgefuellt ({grund}). Erwartet "
|
|
163
|
+
f"wird '{INAKTIV}' - ein Kandidat sagt, dass er noch nicht aktiv ist, statt "
|
|
164
|
+
f"die Angabe offen zu lassen")
|
|
165
|
+
|
|
166
|
+
rechte = os.path.join(root, *man["permissions_file"].split("/"))
|
|
167
|
+
if os.path.exists(rechte):
|
|
168
|
+
inhalt = read(rechte)
|
|
169
|
+
if TBD_RE.search(inhalt) or PLACEHOLDER_RE.search(inhalt):
|
|
170
|
+
err(f"{man['permissions_file']}: enthält noch Platzhalter "
|
|
171
|
+
f"(check-overlay-ready)")
|
|
172
|
+
else:
|
|
173
|
+
err(f"{man['permissions_file']}: fehlt - ohne Berechtigungsdatei ist kein "
|
|
174
|
+
f"Kandidat vollstaendig (check-overlay-ready)")
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
# Pruefung 28: Ein Strukturpfad des Frameworks gehoert nicht in <EXCLUDED_PATHS>.
|
|
178
|
+
#
|
|
179
|
+
# Zwei Schutzziele, zwei Kategorien - der Schutz-Hook unterscheidet sie seit D-30 und die
|
|
180
|
+
# Berechtigungsdatei ebenfalls: <EXCLUDED_PATHS> wird dort zu einer 'read'- UND einer
|
|
181
|
+
# 'write'-Verweigerung, die Strukturpfade stehen ausschliesslich als 'write'-Verweigerung
|
|
182
|
+
# bei 'read allow **'. Die Overlay-Vorlage und die Laufzeitregel fuehrten sie bis 0.31.0
|
|
183
|
+
# unter "weder lesen noch aendern" - genau die Pfade, die der KI-Client als
|
|
184
|
+
# Anweisungsquelle laden soll (B07). Wer die Vorlage woertlich ausfuellt, erzeugt damit
|
|
185
|
+
# eine Lesesperre auf die eigenen Regeldateien. Diese Pruefung findet den Fall im
|
|
186
|
+
# Repositorium, also bevor eine Installation entsteht (D-55).
|
|
187
|
+
STRUKTURPFAD_MARKER = (
|
|
188
|
+
"<RUNTIME_DIR>", "<ROOT_INSTRUCTION_FILE>", "<CORE_DIR>", "<RULES_DIR>",
|
|
189
|
+
".koolie/project-overlay/", "framework/", "AGENTS.md", "CLAUDE.md", ".devin/", ".claude/",
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# Die Beschriftung der Deklarationszeile - in der Overlay-Vorlage eine Tabellenzeile, in
|
|
193
|
+
# der Laufzeitregel ein Listeneintrag. Beide beginnen mit derselben Bezeichnung.
|
|
194
|
+
DEKLARATION_RE = re.compile(r"^\s*(?:\|\s*|-\s+)Ausgeschlossene Pfade")
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _excluded_paths_traeger(root: str, man: dict) -> list[str]:
|
|
198
|
+
"""Dateien, die <EXCLUDED_PATHS> deklarieren - Quelle und Installation."""
|
|
199
|
+
kandidaten = [
|
|
200
|
+
os.path.join(KERN, "templates", "project-overlay", "OVERLAY.md"),
|
|
201
|
+
os.path.join(KERN, "framework", "runtime", "rules", "20-project-overlay.md"),
|
|
202
|
+
os.path.join(".koolie/project-overlay", "OVERLAY.md"),
|
|
203
|
+
]
|
|
204
|
+
runtime_dir = (man or {}).get("runtime_dir")
|
|
205
|
+
if runtime_dir:
|
|
206
|
+
kandidaten.append(os.path.join(runtime_dir.replace("/", os.sep), "rules",
|
|
207
|
+
regeldatei(man, "20-project-overlay.md")))
|
|
208
|
+
treffer = []
|
|
209
|
+
for rel in kandidaten:
|
|
210
|
+
pfad = os.path.join(root, rel)
|
|
211
|
+
if os.path.isfile(pfad) and pfad not in treffer:
|
|
212
|
+
treffer.append(pfad)
|
|
213
|
+
return treffer
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def check_excluded_paths(root: str, man: dict) -> None:
|
|
217
|
+
"""Pruefung 28 (D-55): Ein Schreibschutz ist kein Leseverbot.
|
|
218
|
+
|
|
219
|
+
Geprueft wird die **Deklarationszeile** von <EXCLUDED_PATHS>: Sie darf keinen
|
|
220
|
+
Strukturpfad des Frameworks nennen. Der Nachweis ist eine Textpruefung - dass die
|
|
221
|
+
Berechtigungsdatei die beiden Kategorien trennt, prueft Pruefung 2.
|
|
222
|
+
|
|
223
|
+
Nur die Deklaration, nicht jede Nennung: Beide Traeger erklaeren im Fliesstext
|
|
224
|
+
ausdruecklich, dass die Strukturpfade **nicht** hierher gehoeren, und diese Saetze
|
|
225
|
+
nennen beides in einer Zeile. Eine Pruefung, die jede Nennung meldet, wuerde genau
|
|
226
|
+
den richtigen Text beanstanden. Erkannt wird die Deklaration an ihrer Beschriftung
|
|
227
|
+
(DEKLARATION_RE) - und weil eine verlorene Beschriftung eine Pruefung erzeugt, die
|
|
228
|
+
leise besteht, ist auch ihr Fehlen ein Fehler (D-23).
|
|
229
|
+
"""
|
|
230
|
+
for pfad in _excluded_paths_traeger(root, man):
|
|
231
|
+
rel = os.path.relpath(pfad, root).replace(os.sep, "/")
|
|
232
|
+
zeilen = read(pfad).splitlines()
|
|
233
|
+
deklarationen = [(i, z) for i, z in enumerate(zeilen, 1)
|
|
234
|
+
if "<EXCLUDED_PATHS>" in z and DEKLARATION_RE.match(z)]
|
|
235
|
+
if not deklarationen and any("<EXCLUDED_PATHS>" in z for z in zeilen):
|
|
236
|
+
err(f"{rel}: nennt <EXCLUDED_PATHS>, aber keine Zeile ist als Deklaration "
|
|
237
|
+
f"erkennbar (Beschriftung 'Ausgeschlossene Pfade'). Pruefung 28 prueft "
|
|
238
|
+
f"damit nichts und bestuende leise - die Beschriftung ist Teil des "
|
|
239
|
+
f"Nachweises (D-23, D-55)")
|
|
240
|
+
for i, zeile in deklarationen:
|
|
241
|
+
gefunden = [m for m in STRUKTURPFAD_MARKER if m in zeile]
|
|
242
|
+
if not gefunden:
|
|
243
|
+
continue
|
|
244
|
+
err(f"{rel}:{i}: Die Deklaration von <EXCLUDED_PATHS> nennt "
|
|
245
|
+
f"{', '.join(gefunden)}. <EXCLUDED_PATHS> wird in der Berechtigungsdatei zu "
|
|
246
|
+
f"einer 'read'- UND einer 'write'-Verweigerung; die Strukturpfade des "
|
|
247
|
+
f"Frameworks sind integritaetsgeschuetzt, nicht vertraulich - sie gehoeren "
|
|
248
|
+
f"in <READ_ONLY_PATHS>. Ein Projekt, das dieser Zeile folgt, sperrt den "
|
|
249
|
+
f"Lesezugriff auf seine eigenen Regeldateien; der KI-Client kann die "
|
|
250
|
+
f"Anweisungen dann nicht laden, die er befolgen soll (B07, D-55)")
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
# --- Pruefung 51 -------------------------------------------------------------------
|
|
254
|
+
# Eine Regel kann als SATZ oder als AUSFUELLSCHLITZ ausgedrueckt sein, und ein Sweep nach
|
|
255
|
+
# einer Marke findet nur den Satz. 0.33.0 hat die Domain-Ausnahme in sechzehn Traegern
|
|
256
|
+
# angefasst, davon acht anweisenden - darunter eine Datei im selben Verzeichnis; die
|
|
257
|
+
# Overlay-Laufzeitfassung war nicht darunter, weil dort kein Satz stand. Dreiunddreissig
|
|
258
|
+
# Releases lang bot die Overlay-Laufzeitfassung damit an, was ihre eigene Quelle
|
|
259
|
+
# ausdruecklich ausschliesst (D-150, Grenzfall G-13).
|
|
260
|
+
#
|
|
261
|
+
# ABGELEITET, NICHT GEPFLEGT: Die Feldmenge stammt aus der Kontextquellentabelle der
|
|
262
|
+
# Overlay-Vorlage. Traegt eine Zeile dort einen FESTEN Wert in der Freigabespalte - also
|
|
263
|
+
# keinen <TBD> -, dann ist der Wert entschieden, und die Laufzeitfassung darf fuer
|
|
264
|
+
# dasselbe Feld keinen Schlitz fuehren. Traegt die Quelle selbst einen Schlitz, bleibt er
|
|
265
|
+
# in beiden zulaessig; die Zeile der MCP-Server belegt das als Gegenprobe.
|
|
266
|
+
#
|
|
267
|
+
# WAS SIE NICHT LEISTET: Sie vergleicht Feldnamen, nicht Werte. Ob der eingetragene feste
|
|
268
|
+
# Wert derselbe ist, sieht sie nicht - das ist FW-KO-05 und laeuft als Durchsicht.
|
|
269
|
+
P51_QUELLE = KERN + "/templates/project-overlay/OVERLAY.md"
|
|
270
|
+
P51_LAUFZEIT = KERN + "/framework/runtime/rules/20-project-overlay.md"
|
|
271
|
+
P51_TABELLENKOPF = "| Kontextquelle | Kontextklasse | Freigabe | Bedingungen |"
|
|
272
|
+
P51_KLAMMER_RE = re.compile(r"\s*\([^)]*\)\s*$")
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def _51_feldname(zelle: str) -> str:
|
|
276
|
+
"""Der blosse Feldname einer Zeile - ohne Fettmarkierung und ohne Klammerzusatz.
|
|
277
|
+
|
|
278
|
+
'Freigegebene externe Domains (Fetch)' und 'Freigegebene externe Domains' sind
|
|
279
|
+
dasselbe Feld; die Klammer sagt, ueber welches Werkzeug es wirkt.
|
|
280
|
+
"""
|
|
281
|
+
name = zelle.replace("**", "").strip()
|
|
282
|
+
return P51_KLAMMER_RE.sub("", name).strip()
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def check_overlay_schlitze(root: str) -> None:
|
|
286
|
+
"""Pruefung 51 (D-150): Kein Schlitz fuer einen Wert, den die Overlay-Vorlage festlegt."""
|
|
287
|
+
qpfad = os.path.join(root, P51_QUELLE.replace("/", os.sep))
|
|
288
|
+
lpfad = os.path.join(root, P51_LAUFZEIT.replace("/", os.sep))
|
|
289
|
+
if not os.path.isfile(qpfad) or not os.path.isfile(lpfad):
|
|
290
|
+
err(f"{P51_QUELLE} oder {P51_LAUFZEIT} fehlt – Prüfung 51 hat ihren Gegenstand "
|
|
291
|
+
f"verloren; sie bestünde sonst leise (D-23)")
|
|
292
|
+
return
|
|
293
|
+
quelle = read(qpfad).replace("\r\n", "\n")
|
|
294
|
+
if P51_TABELLENKOPF not in quelle:
|
|
295
|
+
err(f"{P51_QUELLE}: die Kontextquellentabelle mit dem Kopf "
|
|
296
|
+
f"'{P51_TABELLENKOPF}' ist nicht mehr auffindbar. Prüfung 51 leitet ihre "
|
|
297
|
+
f"Feldmenge daraus ab und hätte ohne sie nichts zu prüfen (D-23)")
|
|
298
|
+
return
|
|
299
|
+
rest = quelle.split(P51_TABELLENKOPF, 1)[1]
|
|
300
|
+
festgelegt = []
|
|
301
|
+
for zeile in rest.split("\n")[1:]:
|
|
302
|
+
if not zeile.startswith("|"):
|
|
303
|
+
break
|
|
304
|
+
zellen = tabellenzellen(zeile)
|
|
305
|
+
if len(zellen) < 3:
|
|
306
|
+
continue
|
|
307
|
+
if TBD_RE.search(zellen[2]):
|
|
308
|
+
continue
|
|
309
|
+
festgelegt.append((_51_feldname(zellen[0]), zellen[2].replace("**", "").strip()))
|
|
310
|
+
if not festgelegt:
|
|
311
|
+
err(f"{P51_QUELLE}: keine Zeile der Kontextquellentabelle trägt einen festen "
|
|
312
|
+
f"Freigabewert. Prüfung 51 hätte damit keinen Gegenstand mehr (D-23)")
|
|
313
|
+
return
|
|
314
|
+
laufzeit = read(lpfad).replace("\r\n", "\n")
|
|
315
|
+
for name, wert in festgelegt:
|
|
316
|
+
for zeile in laufzeit.split("\n"):
|
|
317
|
+
roh = zeile.lstrip("-* ").strip()
|
|
318
|
+
if not roh.startswith(name + ":"):
|
|
319
|
+
continue
|
|
320
|
+
if TBD_RE.search(roh):
|
|
321
|
+
err(f"{P51_LAUFZEIT}: Das Feld '{name}' trägt einen Ausfüllschlitz, "
|
|
322
|
+
f"obwohl {P51_QUELLE} seinen Wert auf '{wert}' festlegt. Eine Regel "
|
|
323
|
+
f"kann als Satz oder als Schlitz ausgedrückt sein – ein Sweep nach "
|
|
324
|
+
f"der Formulierung findet nur den Satz, und die Laufzeitfassung ist "
|
|
325
|
+
f"die, die in jede Sitzung lädt (D-150, Grenzfall G-13)")
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
# --- Pruefung 52 -------------------------------------------------------------------
|
|
329
|
+
# Eine Kurzfassung, die den einschraenkenden Halbsatz der Langform weglaesst, kehrt ihre
|
|
330
|
+
# Aussage um. Die Wurzel-Anweisungsdatei trennt seit D-53 zwei Saetze: Anwendungslogik mit
|
|
331
|
+
# Sicherheitsbezug ist Kontrollstufe hoch und nach Freigabe umsetzbar - tatsaechliche
|
|
332
|
+
# Berechtigungen und Betriebs-, Infrastruktur- und Sicherheitskonfigurationen sind V6 und
|
|
333
|
+
# auch nach Freigabe nicht delegierbar. Zwei Fassungen fuehrten beides in EINER
|
|
334
|
+
# Aufzaehlung, deren Rechtsfolge die Freigabe war, und stellten damit ein
|
|
335
|
+
# Delegationsverbot auf die freigebbare Seite - sechzig Releases lang (D-151,
|
|
336
|
+
# Grenzfaelle G-05 und G-06).
|
|
337
|
+
#
|
|
338
|
+
# ABGELEITET: Die Begriffe stammen aus der V6-Zeile der Delegationsverbotsliste. Die
|
|
339
|
+
# Schreibvarianten stehen daneben, wie bei Pruefung 29 - das Projekt fuehrt
|
|
340
|
+
# 'Sicherheitskonfiguration' und 'Security-Konfiguration' synonym, und eine Pruefung, die
|
|
341
|
+
# nur eine Schreibweise kennt, findet die Haelfte.
|
|
342
|
+
#
|
|
343
|
+
# AUSGENOMMEN ist die Langform, aus der die Begriffe stammen: Dort steht die Abgrenzung
|
|
344
|
+
# zu V6, und sie MUSS beide Seiten in einem Absatz nennen. Die Ausnahme ist abgeleitet -
|
|
345
|
+
# es ist die Datei, aus der gelesen wurde, nicht ein gepflegter Name.
|
|
346
|
+
#
|
|
347
|
+
# WAS SIE NICHT LEISTET: Sie liest Woerter, keine Bedeutung. Ein Text, der dieselbe
|
|
348
|
+
# Aussage ohne diese Begriffe trifft, entgeht ihr - dieselbe Grenze wie bei Pruefung 29.
|
|
349
|
+
P52_RISIKO = KERN + "/framework/core/09-risk-model.md"
|
|
350
|
+
P52_V6_RE = re.compile(r"^\|\s*V6\s*\|([^|]*)\|", re.M)
|
|
351
|
+
# Schreibvarianten je Begriff der V6-Zeile. Links der Wortstamm, wie er dort steht.
|
|
352
|
+
P52_VARIANTEN = {
|
|
353
|
+
"Produktionssystem": r"Produktionssystem",
|
|
354
|
+
"Infrastruktur": r"Infrastruktur",
|
|
355
|
+
"Berechtigung": r"Berechtigung",
|
|
356
|
+
"Sicherheitskonfiguration": r"Sicherheitskonfiguration|Security-Konfiguration",
|
|
357
|
+
}
|
|
358
|
+
P52_STUFE_RE = re.compile(r"Kontrollstufe\s+\*{0,2}hoch")
|
|
359
|
+
P52_FOLGE_RE = re.compile(r"Umsetzung[^.;]{0,120}Freigabe")
|
|
360
|
+
P52_EINZELN_RE = re.compile(r"^\s*(?:[-*+]\s|\d+\.\s|\|)")
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def _52_v6_begriffe(root: str) -> list:
|
|
364
|
+
"""Die Begriffe der V6-Zeile, auf ihren Stamm gebracht - abgeleitet, nicht gepflegt."""
|
|
365
|
+
pfad = os.path.join(root, P52_RISIKO.replace("/", os.sep))
|
|
366
|
+
if not os.path.isfile(pfad):
|
|
367
|
+
return []
|
|
368
|
+
m = P52_V6_RE.search(read(pfad).replace("\r\n", "\n"))
|
|
369
|
+
if not m:
|
|
370
|
+
return []
|
|
371
|
+
treffer = []
|
|
372
|
+
for stamm, muster in P52_VARIANTEN.items():
|
|
373
|
+
if re.search(stamm, m.group(1)):
|
|
374
|
+
treffer.append((stamm, re.compile(muster)))
|
|
375
|
+
return treffer
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def _52_einheiten(text: str):
|
|
379
|
+
"""Liefert die Pruefeinheiten: Listenpunkte und Tabellenzeilen einzeln, Prosa als Absatz.
|
|
380
|
+
|
|
381
|
+
Die Einheit muss die des Lesers sein. Wer einen Listenpunkt liest, liest ihn allein;
|
|
382
|
+
wer einen Absatz liest, liest ihn ganz. Eine Pruefung ueber die ganze Datei fände in
|
|
383
|
+
jeder normativen Datei beides und meldete ueberall.
|
|
384
|
+
"""
|
|
385
|
+
absatz = []
|
|
386
|
+
for zeile in text.replace("\r\n", "\n").split("\n"):
|
|
387
|
+
if not zeile.strip() or P52_EINZELN_RE.match(zeile):
|
|
388
|
+
if absatz:
|
|
389
|
+
yield "\n".join(absatz)
|
|
390
|
+
absatz = []
|
|
391
|
+
if zeile.strip():
|
|
392
|
+
yield zeile
|
|
393
|
+
continue
|
|
394
|
+
absatz.append(zeile)
|
|
395
|
+
if absatz:
|
|
396
|
+
yield "\n".join(absatz)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def check_v6_freigabefolge(root: str) -> None:
|
|
400
|
+
"""Pruefung 52 (D-151): Kein V6-Gegenstand in einer Aufzaehlung mit Freigabefolge."""
|
|
401
|
+
begriffe = _52_v6_begriffe(root)
|
|
402
|
+
if not begriffe:
|
|
403
|
+
err(f"{P52_RISIKO}: die Zeile 'V6' der Delegationsverbotsliste ist nicht mehr "
|
|
404
|
+
f"auffindbar oder nennt keinen der bekannten Begriffe. Prüfung 52 leitet "
|
|
405
|
+
f"ihren Gegenstand daraus ab und hätte ohne sie nichts zu prüfen (D-23)")
|
|
406
|
+
return
|
|
407
|
+
ausgenommen = os.path.join(root, P52_RISIKO.replace("/", os.sep))
|
|
408
|
+
for pfad in _normative_traeger(root):
|
|
409
|
+
if os.path.abspath(pfad) == os.path.abspath(ausgenommen):
|
|
410
|
+
continue
|
|
411
|
+
rel = os.path.relpath(pfad, root).replace(os.sep, "/")
|
|
412
|
+
for einheit in _52_einheiten(read(pfad)):
|
|
413
|
+
if not P52_STUFE_RE.search(einheit) or not P52_FOLGE_RE.search(einheit):
|
|
414
|
+
continue
|
|
415
|
+
for stamm, muster in begriffe:
|
|
416
|
+
if muster.search(einheit):
|
|
417
|
+
err(f"{rel}: '{stamm}' steht in einer Aufzählung, deren Rechtsfolge "
|
|
418
|
+
f"eine Freigabe ist ('…{P52_FOLGE_RE.search(einheit).group(0)[:60]}…'). "
|
|
419
|
+
f"V6 ist auch nach Freigabe nicht delegierbar; die Abgrenzung "
|
|
420
|
+
f"trennt Anwendungslogik von Betrieb (D-53, D-151, Grenzfälle "
|
|
421
|
+
f"G-05 und G-06)")
|
|
422
|
+
break
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def _normative_traeger(root: str):
|
|
426
|
+
"""Die anweisenden Fassungen: Wurzel-Anweisungsdatei, Regelablage, Langform,
|
|
427
|
+
Overlay-Vorlage, Skills und Checklisten - die sechs, die FW-KO-05 gegeneinander hält."""
|
|
428
|
+
pfade = []
|
|
429
|
+
p = os.path.join(root, KERN, "framework", "runtime", "root-instruction.md")
|
|
430
|
+
if os.path.isfile(p):
|
|
431
|
+
pfade.append(p)
|
|
432
|
+
for teil in (("framework", "runtime", "rules"), ("framework", "core"),
|
|
433
|
+
("checklists",), ("templates", "project-overlay")):
|
|
434
|
+
verz = os.path.join(root, KERN, *teil)
|
|
435
|
+
if not os.path.isdir(verz):
|
|
436
|
+
continue
|
|
437
|
+
for name in sorted(os.listdir(verz)):
|
|
438
|
+
if name.endswith(".md"):
|
|
439
|
+
pfade.append(os.path.join(verz, name))
|
|
440
|
+
skills = os.path.join(root, KERN, "framework", "skills")
|
|
441
|
+
if os.path.isdir(skills):
|
|
442
|
+
for name in sorted(os.listdir(skills)):
|
|
443
|
+
p = os.path.join(skills, name, "SKILL.md")
|
|
444
|
+
if os.path.isfile(p):
|
|
445
|
+
pfade.append(p)
|
|
446
|
+
return pfade
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
# --- Pruefung 55 und 56 --------------------------------------------------------------
|
|
450
|
+
# ANLASS: der Durchgang durch die Vorbedingungen der dreizehn Testblaetter (2026-09-18).
|
|
451
|
+
# Er hat zwei Dinge gefunden, die nichts gemeldet hat.
|
|
452
|
+
#
|
|
453
|
+
# ERSTENS: Ein Overlay darf einen Platzhalter durch seinen WERT ERSETZEN statt ihn zu
|
|
454
|
+
# BINDEN. Fuer das Overlay selbst ist das folgenlos - es nennt ja den Wert. Fuer jeden
|
|
455
|
+
# KERNTEXT, der denselben Platzhalter traegt, ist es das nicht: Im Uebungsrepositorium
|
|
456
|
+
# standen 65 Fundstellen von fuenf Pflichtplatzhaltern in der geladenen Laufzeitschicht,
|
|
457
|
+
# die kein Leser aufloesen konnte - <ISSUE_TRACKER> allein in vierzehn Traegern.
|
|
458
|
+
# Der Validator meldete 0 Fehler, 0 Warnungen.
|
|
459
|
+
#
|
|
460
|
+
# ZWEITENS: Eine Vorbedingung darf einen Traeger verlangen, den dasselbe Overlay sperrt.
|
|
461
|
+
# SK-012-P01 verlangt die Merge-Request-Vorlage; ihr Pfad liegt unter .github/**, und das
|
|
462
|
+
# steht im Uebungs-Overlay unter <EXCLUDED_PATHS>. Die Zelle war damit nie fahrbar.
|
|
463
|
+
#
|
|
464
|
+
# WAS 55 NICHT LEISTET: (b) prueft, ob der Platzhalter GENANNT wird, nicht ob der Wert
|
|
465
|
+
# daneben richtig ist. Eine Bindung an den falschen Wert laeuft durch.
|
|
466
|
+
# WAS 56 NICHT LEISTET: Sie loest ueber die Bindungszeile auf. Eine Vorbedingung, die
|
|
467
|
+
# einen ausgeschlossenen Pfad WOERTLICH nennt statt ueber einen Platzhalter, entgeht ihr.
|
|
468
|
+
P55_REGISTER = KERN + "/docs/PLACEHOLDER_REGISTRY.md"
|
|
469
|
+
P55_VORLAGE = KERN + "/templates/project-overlay/OVERLAY.md"
|
|
470
|
+
P55_LAUFZEIT = (KERN + "/framework/runtime/rules", KERN + "/framework/skills")
|
|
471
|
+
P55_ZEILE_RE = re.compile(r"^\|\s*`<([A-Z][A-Z0-9_]*)>`\s*\|")
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
def _p55_pflicht(root: str) -> list:
|
|
475
|
+
"""(Name, Ort) je Platzhalter mit 'Pflicht vor Aktivierung' = ja - abgeleitet."""
|
|
476
|
+
pfad = os.path.join(root, P55_REGISTER.replace("/", os.sep))
|
|
477
|
+
if not os.path.isfile(pfad):
|
|
478
|
+
err(f"{P55_REGISTER} fehlt - Prüfung 55 hat ihren Gegenstand verloren; sie "
|
|
479
|
+
f"bestünde sonst leise (D-23)")
|
|
480
|
+
return []
|
|
481
|
+
raus = []
|
|
482
|
+
for zeile in read(pfad).replace("\r\n", "\n").split("\n"):
|
|
483
|
+
z = zeile.strip()
|
|
484
|
+
treffer = P55_ZEILE_RE.match(z)
|
|
485
|
+
if not treffer:
|
|
486
|
+
continue
|
|
487
|
+
zellen = tabellenzellen(z)
|
|
488
|
+
if len(zellen) > 4 and zellen[4].startswith("ja"):
|
|
489
|
+
raus.append((treffer.group(1), zellen[2]))
|
|
490
|
+
if not raus:
|
|
491
|
+
err(f"{P55_REGISTER}: keine Zeile trägt 'Pflicht vor Aktivierung' = ja. Prüfung "
|
|
492
|
+
f"55 leitet ihre Menge von dort ab und hätte damit nichts zu prüfen (D-23)")
|
|
493
|
+
return raus
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
def check_pflichtplatzhalter(root: str) -> None:
|
|
497
|
+
"""Pruefung 55a: Die Overlay-Vorlage bietet jeden Pflichtplatzhalter an."""
|
|
498
|
+
pfad = os.path.join(root, P55_VORLAGE.replace("/", os.sep))
|
|
499
|
+
if not os.path.isfile(pfad):
|
|
500
|
+
return
|
|
501
|
+
vorlage = read(pfad)
|
|
502
|
+
for name, ort in _p55_pflicht(root):
|
|
503
|
+
if not ort.lower().startswith("overlay"):
|
|
504
|
+
continue # anderswo gesetzt - die Vorlage muss ihn nicht anbieten
|
|
505
|
+
if name not in vorlage:
|
|
506
|
+
err(f"{P55_VORLAGE}: Der Platzhalter <{name}> ist im Register als 'Pflicht "
|
|
507
|
+
f"vor Aktivierung' geführt und dort in '{ort}' verortet, kommt in der "
|
|
508
|
+
f"Vorlage aber nicht vor. Ein Projekt, das die Vorlage ausfüllt, "
|
|
509
|
+
f"begegnet ihm nie (D-160)")
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
def check_platzhalterbindung(root: str, man: dict) -> None:
|
|
513
|
+
"""Pruefung 55b (--strict-overlay): Das aktive Overlay BINDET, statt zu ersetzen.
|
|
514
|
+
|
|
515
|
+
🔴 SIE PRUEFT SEIT 0.84.0 DIE BINDUNG UND NICHT MEHR DIE NENNUNG (K-88, D-257).
|
|
516
|
+
Bis 0.83.0 fragte sie `if name in text`, also die BUCHSTABEN des Platzhalternamens
|
|
517
|
+
irgendwo im Overlay - und meldete am Uebungsrepositorium NULL, waehrend 14 von 26
|
|
518
|
+
Pflichtplatzhaltern dort nirgends mit spitzen Klammern standen. Ihr eigener
|
|
519
|
+
Meldungstext sagte dabei "ist im Overlay aber nirgends gebunden".
|
|
520
|
+
|
|
521
|
+
Eine Bindung, die eine Teilzeichenkette ist, sagt nichts ueber einen Wert.
|
|
522
|
+
|
|
523
|
+
🔴 Und die Gegenprobe deckte es mit: `BINDUNGEN` in `probe-pruefungen.py` schrieb
|
|
524
|
+
`ISSUE_TRACKER` ohne Klammern und nannte das eine Bindung. Zwei Stellen, die
|
|
525
|
+
einander decken - derselbe Befundtyp wie bei `LINK_ROOTS` und `OPTIONAL_RUNTIME_RE`
|
|
526
|
+
(0.57.0). Die Sonde `55d` misst jetzt genau den Unterschied.
|
|
527
|
+
"""
|
|
528
|
+
overlay = os.path.join(root, ".koolie/project-overlay", "OVERLAY.md")
|
|
529
|
+
if not os.path.isfile(overlay):
|
|
530
|
+
return
|
|
531
|
+
text = read(overlay)
|
|
532
|
+
genannt = {}
|
|
533
|
+
for basis in P55_LAUFZEIT:
|
|
534
|
+
wurzel = os.path.join(root, basis.replace("/", os.sep))
|
|
535
|
+
if not os.path.isdir(wurzel):
|
|
536
|
+
continue
|
|
537
|
+
for ordner, _, dateien in os.walk(wurzel):
|
|
538
|
+
for n in sorted(dateien):
|
|
539
|
+
if not n.endswith(".md"):
|
|
540
|
+
continue
|
|
541
|
+
p = os.path.join(ordner, n)
|
|
542
|
+
inhalt = read(p)
|
|
543
|
+
rel = os.path.relpath(p, root).replace(os.sep, "/")
|
|
544
|
+
for name, _ in _p55_pflicht(root):
|
|
545
|
+
if f"<{name}>" in inhalt:
|
|
546
|
+
genannt.setdefault(name, []).append(rel)
|
|
547
|
+
for name, traeger in sorted(genannt.items()):
|
|
548
|
+
# Der Name IN SPITZEN KLAMMERN - die Schreibweise, die den Kerntext aufloest.
|
|
549
|
+
# Ein blosses Vorkommen der Buchstaben ist eine Nennung, keine Bindung (D-257).
|
|
550
|
+
if f"<{name}>" in text:
|
|
551
|
+
continue
|
|
552
|
+
err(f".koolie/project-overlay/OVERLAY.md: Der Pflichtplatzhalter <{name}> wird von "
|
|
553
|
+
f"{len(traeger)} Träger(n) der geladenen Schicht genannt (z. B. "
|
|
554
|
+
f"{traeger[0]}), ist im Overlay aber nirgends gebunden. Ein Overlay, das den "
|
|
555
|
+
f"Platzhalter durch seinen Wert ersetzt statt ihn zu binden, lässt jeden "
|
|
556
|
+
f"Kerntext unauflösbar, der ihn trägt (D-160)")
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
P56_KATALOG = KERN + "/tests/TEST_CATALOG.md"
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
def _p56_ausgeschlossen(text: str) -> list:
|
|
563
|
+
"""Die Globs aus der <EXCLUDED_PATHS>-Zeile des aktiven Overlays."""
|
|
564
|
+
for zeile in text.replace("\r\n", "\n").split("\n"):
|
|
565
|
+
if "<EXCLUDED_PATHS>" not in zeile:
|
|
566
|
+
continue
|
|
567
|
+
zellen = tabellenzellen(zeile.strip())
|
|
568
|
+
for zelle in zellen:
|
|
569
|
+
if "<EXCLUDED_PATHS>" in zelle:
|
|
570
|
+
continue
|
|
571
|
+
treffer = re.findall(r"`([^`]+)`", zelle)
|
|
572
|
+
if treffer:
|
|
573
|
+
return treffer
|
|
574
|
+
return []
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
def _p56_deckt(glob: str, pfad: str) -> bool:
|
|
578
|
+
"""Deckt das Glob-Muster den Pfad? Segmentweise, nicht nach Pfadanfang.
|
|
579
|
+
|
|
580
|
+
DER ERSTE ENTWURF VERGLICH NUR DAS ERSTE SEGMENT, und das hat in EINEM Release
|
|
581
|
+
zweimal falsch gemeldet: erst bei drei Zellen, die <EXCLUDED_PATHS> selbst zum
|
|
582
|
+
Gegenstand haben, dann bei `.github/pull_request_template.md` gegen
|
|
583
|
+
`.github/workflows/**` - derselbe Anfang, verschiedene Pfade. Eine Pruefung, die
|
|
584
|
+
Pfadanfaenge vergleicht, meldet jede Nachbardatei mit.
|
|
585
|
+
"""
|
|
586
|
+
muster = re.escape(glob).replace(r"\*\*", "\x00").replace(r"\*", "[^/]*")
|
|
587
|
+
muster = muster.replace("\x00", ".*")
|
|
588
|
+
return re.fullmatch(muster, pfad) is not None
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
def _p56_bindung(text: str, name: str) -> str:
|
|
592
|
+
"""Der Wert, den die Bindungszeile des Platzhalters traegt - in BEIDEN Schreibweisen.
|
|
593
|
+
|
|
594
|
+
🔴 GEFUNDEN DURCH DIE ABHILFE ZU K-88, AM SELBEN TAG (D-261). Pruefung 55b
|
|
595
|
+
verlangt seit 0.84.0 den Platzhalternamen IN SPITZEN KLAMMERN; diese Funktion suchte
|
|
596
|
+
ihn OHNE - `f"`{name}`"`. Nach der Bindung der vierzehn Platzhalter im
|
|
597
|
+
Uebungs-Overlay haette Pruefung 56 ihre Zeilen nicht mehr gefunden und waere leise
|
|
598
|
+
gruen geblieben; Sonde 56a ist genau daran gefallen.
|
|
599
|
+
|
|
600
|
+
Zwei Pruefungen, die dieselbe Zeile lesen, muessen sie gleich lesen - oder jede
|
|
601
|
+
fuer ihren eigenen Gegenstand, und das ausdruecklich.
|
|
602
|
+
|
|
603
|
+
Hier gilt das Zweite: **55b prueft die SCHREIBWEISE der Bindung, 56 den WERT
|
|
604
|
+
daneben.** Fuer den Wert ist gleichgueltig, wie der Name geschrieben steht - und ein
|
|
605
|
+
Overlay aus dem Bestand traegt ihn weiter ohne Klammern. Die Funktion nimmt deshalb
|
|
606
|
+
beide Formen; eine Pruefung, die einen Wert nicht mehr findet, meldet keinen Fehler,
|
|
607
|
+
sondern schweigt - und das ist die Bauform "die Null durch Konstruktion".
|
|
608
|
+
|
|
609
|
+
**Dieselbe Bauform wie D-248 und D-243:** Die Meldung entsteht durch die Abhilfe,
|
|
610
|
+
und zwei Pruefungen standen gegeneinander.
|
|
611
|
+
"""
|
|
612
|
+
offen = None
|
|
613
|
+
for zeile in text.replace("\r\n", "\n").split("\n"):
|
|
614
|
+
z = zeile.strip()
|
|
615
|
+
if not z.startswith("|"):
|
|
616
|
+
continue
|
|
617
|
+
if f"`<{name}>`" not in z and f"`{name}`" not in z:
|
|
618
|
+
continue
|
|
619
|
+
zellen = tabellenzellen(z)
|
|
620
|
+
wert = " ".join(zellen[1:])
|
|
621
|
+
# \U0001f534 EINE ZEILE MIT `<TBD...>` BINDET NICHTS (D-261, zweiter Teil). Die
|
|
622
|
+
# Overlay-VORLAGE traegt zu jedem Pflichtplatzhalter eine Zeile mit offenem
|
|
623
|
+
# Wert; wer sie stehen laesst und den Wert weiter unten bindet, wurde bis
|
|
624
|
+
# 0.83.0 mit dem `<TBD>` der Vorlage gemessen - und die Pruefung schwieg.
|
|
625
|
+
# Aufgefallen ist es erst, als 55b die spitzen Klammern verlangte und diese
|
|
626
|
+
# Funktion dieselbe Schreibweise lesen musste: Die Enge der einen Stelle hat
|
|
627
|
+
# verhindert, dass die zweite auffaellt (die Bauform von 0.57.0).
|
|
628
|
+
if re.search(r"<TBD[:>]", wert):
|
|
629
|
+
offen = offen or wert
|
|
630
|
+
continue
|
|
631
|
+
return wert
|
|
632
|
+
# Keine gebundene Zeile - der offene Wert ist die ehrlichere Auskunft als "".
|
|
633
|
+
return offen or ""
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
def check_ausgeschlossene_vorbedingung(root: str, man: dict) -> None:
|
|
637
|
+
"""Pruefung 56 (--strict-overlay): Keine Vorbedingung verlangt einen gesperrten Traeger."""
|
|
638
|
+
overlay = os.path.join(root, ".koolie/project-overlay", "OVERLAY.md")
|
|
639
|
+
if not os.path.isfile(overlay):
|
|
640
|
+
return
|
|
641
|
+
otext = read(overlay)
|
|
642
|
+
globs = _p56_ausgeschlossen(otext)
|
|
643
|
+
if not globs:
|
|
644
|
+
err(f".koolie/project-overlay/OVERLAY.md: Die Zeile zu <EXCLUDED_PATHS> führt keine "
|
|
645
|
+
f"Pfade in Backticks. Prüfung 56 leitet ihre Menge von dort ab und hätte "
|
|
646
|
+
f"damit nichts zu prüfen (D-23)")
|
|
647
|
+
return
|
|
648
|
+
dateien = [os.path.join(root, P56_KATALOG.replace("/", os.sep))]
|
|
649
|
+
for ordner, _, namen in os.walk(os.path.join(root, KERN.replace("/", os.sep),
|
|
650
|
+
"framework")):
|
|
651
|
+
for n in sorted(namen):
|
|
652
|
+
if n == "TESTS.md":
|
|
653
|
+
dateien.append(os.path.join(ordner, n))
|
|
654
|
+
for pfad in dateien:
|
|
655
|
+
if not os.path.isfile(pfad):
|
|
656
|
+
continue
|
|
657
|
+
rel = os.path.relpath(pfad, root).replace(os.sep, "/")
|
|
658
|
+
for zeile in read(pfad).replace("\r\n", "\n").split("\n"):
|
|
659
|
+
z = zeile.strip()
|
|
660
|
+
if not z.startswith("| ") or z.startswith("|---"):
|
|
661
|
+
continue
|
|
662
|
+
zellen = tabellenzellen(z)
|
|
663
|
+
if len(zellen) < 4:
|
|
664
|
+
continue
|
|
665
|
+
vorbed = zellen[2]
|
|
666
|
+
for name in re.findall(r"<([A-Z][A-Z0-9_]*)>", vorbed):
|
|
667
|
+
# DER ZUSCHNITT, UND ER IST BEIM ERSTEN LAUF NOETIG GEWORDEN: Eine Zelle,
|
|
668
|
+
# die <EXCLUDED_PATHS> SELBST nennt, hat die Sperre zum Gegenstand - sie
|
|
669
|
+
# prueft, ob der Client sie achtet. Ohne diese Ausnahme meldete die
|
|
670
|
+
# Pruefung am 2026-09-18 drei solche Zellen (SK-001-N01, SK-010-N02,
|
|
671
|
+
# SK-012-N03) als nicht fahrbar, und alle drei sind es. Eine Pruefung,
|
|
672
|
+
# die ihren eigenen Gegenstand beanstandet, behauptet mehr als ihr Fall
|
|
673
|
+
# hergibt.
|
|
674
|
+
if name == "EXCLUDED_PATHS":
|
|
675
|
+
continue
|
|
676
|
+
wert = _p56_bindung(otext, name)
|
|
677
|
+
if not wert:
|
|
678
|
+
continue
|
|
679
|
+
for pfadangabe in re.findall(r"`([^`]+)`", wert):
|
|
680
|
+
for g in globs:
|
|
681
|
+
if _p56_deckt(g, pfadangabe):
|
|
682
|
+
err(f"{rel}: Die Vorbedingung von '{zellen[0]}' verlangt "
|
|
683
|
+
f"<{name}>; der Wert '{pfadangabe}' liegt unter "
|
|
684
|
+
f"'{g}', das dasselbe Overlay unter <EXCLUDED_PATHS> "
|
|
685
|
+
f"führt - weder lesen noch ändern. Die Zelle ist damit "
|
|
686
|
+
f"nicht fahrbar (D-161)")
|
|
687
|
+
break
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
# --- Pruefung 57: kein ungebundener Pflichtplatzhalter als Vorbedingung -------------
|
|
691
|
+
#
|
|
692
|
+
# DIE KEHRSEITE VON 55b. Pruefung 55b meldet ein aktives Overlay, das einen
|
|
693
|
+
# Pflichtplatzhalter nicht bindet. Eine Testzelle, die genau diesen Zustand als
|
|
694
|
+
# Vorbedingung verlangt, ist damit nur in einem Baum fahrbar, den der Validator
|
|
695
|
+
# beanstandet - eine Pruefung und ein Testfall desselben Repositoriums stehen
|
|
696
|
+
# gegeneinander, und keiner von beiden sagt es.
|
|
697
|
+
#
|
|
698
|
+
# WARUM TEILSAETZE UND NICHT ZELLEN. Eine Vorbedingung nennt haeufig mehrere Zustaende
|
|
699
|
+
# in einer Zelle. Wer die ganze Zelle nach einer Verneinung durchsucht, meldet jede
|
|
700
|
+
# Zelle mit, die irgendwo ein "ohne" traegt - die Bauform, an der Pruefung 56 beim
|
|
701
|
+
# ersten Lauf zweimal zu breit gemeldet hat. Getrennt wird an Semikolon und Punkt.
|
|
702
|
+
#
|
|
703
|
+
# WAS SIE NICHT LEISTET. Sie erkennt die AUFGEZAEHLTEN Wendungen, nicht jede moegliche.
|
|
704
|
+
# "Ein Overlay, in dem der Platzhalter fehlt" entgeht ihr - dieselbe Grenze, die
|
|
705
|
+
# Pruefung 29 bei Bedingungswoertern hat. Die Aufzaehlung steht hier und nirgends sonst.
|
|
706
|
+
P57_VERNEINUNG = (
|
|
707
|
+
"ohne gesetzt",
|
|
708
|
+
"ohne gebunden",
|
|
709
|
+
"ohne belegt",
|
|
710
|
+
"nicht gesetzt",
|
|
711
|
+
"nicht gebunden",
|
|
712
|
+
"nicht belegt",
|
|
713
|
+
"ungebunden",
|
|
714
|
+
)
|
|
715
|
+
|
|
716
|
+
|
|
717
|
+
def _p57_teilsaetze(text: str) -> list:
|
|
718
|
+
"""Die Vorbedingung in Teilsaetze zerlegen - Semikolon und Punkt trennen."""
|
|
719
|
+
return [t.strip() for t in re.split(r"[;.]", text) if t.strip()]
|
|
720
|
+
|
|
721
|
+
|
|
722
|
+
def check_ungebundene_vorbedingung(root: str) -> None:
|
|
723
|
+
"""Pruefung 57: Keine Vorbedingung verlangt einen ungebundenen Pflichtplatzhalter."""
|
|
724
|
+
pflicht = {name for name, _ in _p55_pflicht(root)}
|
|
725
|
+
if not pflicht:
|
|
726
|
+
return # _p55_pflicht hat den verlorenen Gegenstand bereits gemeldet
|
|
727
|
+
for rel in _ueb_katalogdateien(root):
|
|
728
|
+
pfad = os.path.join(root, *rel.split(os.sep))
|
|
729
|
+
if not os.path.isfile(pfad):
|
|
730
|
+
continue
|
|
731
|
+
anzeige = rel.replace(os.sep, "/")
|
|
732
|
+
for zeile in read(pfad).replace("\r\n", "\n").split("\n"):
|
|
733
|
+
z = zeile.strip()
|
|
734
|
+
if not z.startswith("| ") or z.startswith("|---"):
|
|
735
|
+
continue
|
|
736
|
+
zellen = tabellenzellen(z)
|
|
737
|
+
if len(zellen) < 4:
|
|
738
|
+
continue
|
|
739
|
+
for teil in _p57_teilsaetze(zellen[2]):
|
|
740
|
+
namen = [n for n in re.findall(r"<([A-Z][A-Z0-9_]*)>", teil)
|
|
741
|
+
if n in pflicht]
|
|
742
|
+
if not namen:
|
|
743
|
+
continue
|
|
744
|
+
klein = teil.lower()
|
|
745
|
+
marke = next((m for m in P57_VERNEINUNG if m in klein), None)
|
|
746
|
+
if marke is None:
|
|
747
|
+
continue
|
|
748
|
+
err(f"{anzeige}: Die Vorbedingung von '{zellen[0]}' verlangt "
|
|
749
|
+
f"<{namen[0]}> als nicht gesetzt ('{marke}'). Der Platzhalter ist "
|
|
750
|
+
f"im Register 'Pflicht vor Aktivierung', und Pruefung 55b meldet "
|
|
751
|
+
f"genau diesen Zustand im aktiven Overlay als Fehler - die Zelle "
|
|
752
|
+
f"waere nur in einem Baum fahrbar, den der Validator beanstandet. "
|
|
753
|
+
f"Gemeint ist in aller Regel ein gebundener Platzhalter OHNE Wert, "
|
|
754
|
+
f"also ein Ausfuellschlitz (D-166)")
|
|
755
|
+
break
|
|
756
|
+
|
|
757
|
+
# --- Pruefung 60: Der Befehlsschlitz, den der Ausloeser braucht ---------------------
|
|
758
|
+
#
|
|
759
|
+
# ANLASS. Gemessen am 2026-09-18 im fuenften Sitzungstest (CR-2026-091). `FW-SC-01`
|
|
760
|
+
# ist zum dritten Mal gefahren worden und zum dritten Mal nicht abnehmbar gewesen -
|
|
761
|
+
# diesmal aus einem neuen Grund: Der Lauf hat NICHTS geaendert. `fw-change-small`
|
|
762
|
+
# verlangt in Schritt 4, den Testbefehl VOR dem ersten Schreibzugriff auszufuehren;
|
|
763
|
+
# im Messbaum stand `<TEST_COMMAND>` im `ask`-Korb, und `ask` ist im
|
|
764
|
+
# nicht-interaktiven Betrieb eine Abweisung (D-134). Der Lauf hat angehalten und
|
|
765
|
+
# gefragt - regelkonform. Gemessen war der Korb, nicht die Scope-Treue.
|
|
766
|
+
#
|
|
767
|
+
# Der Schreibzuschnitt deckt das SCHREIBEN, nicht das AUSFUEHREN.
|
|
768
|
+
#
|
|
769
|
+
# Derselbe Fehler hat im selben Release `FW-PO-02` einen Durchgang gekostet, und er
|
|
770
|
+
# wiederholt sich bei jeder Wiederholung, weil die Zelle ihn nicht nennt. `FW-SC-02`
|
|
771
|
+
# ist mit 0.59.0 abgenommen worden, weil sein Messbaum den Befehl freigab - seine
|
|
772
|
+
# Zelle sagt es nicht, und wer sie ohne dieses Wissen wiederholt, faellt hinein.
|
|
773
|
+
#
|
|
774
|
+
# GEGENSTAND. Eine `sitzung`-Zelle, deren Ausloeser einen Skill als `/name` aufruft,
|
|
775
|
+
# dessen Frontmatter einen Befehlsschlitz AUSFUEHRT (`Exec(<..._COMMAND>)` unter
|
|
776
|
+
# `permissions`), muss diesen Schlitz in ihrer VORBEDINGUNG nennen.
|
|
777
|
+
#
|
|
778
|
+
# WARUM DAS FRONTMATTER UND NICHT DER FLIESSTEXT. `fw-plan` nennt `<TEST_COMMAND>`
|
|
779
|
+
# in seinen Vorbedingungen und in seiner Teststrategie - es fuehrt den Befehl aber
|
|
780
|
+
# nicht aus, sondern plant ihn. Ein Zuschnitt ueber den Fliesstext haette `FW-FI-02`
|
|
781
|
+
# mitgemeldet, dessen Lauf am 2026-09-18 keinen einzigen Befehl gebraucht hat. Das
|
|
782
|
+
# Frontmatter sagt, was der Skill TUT; der Fliesstext, wovon er redet.
|
|
783
|
+
#
|
|
784
|
+
# GRENZE, UND SIE STEHT HIER. Geprueft wird die NENNUNG des Schlitzes, nicht die
|
|
785
|
+
# Aussage darueber. Eine Vorbedingung, die `<TEST_COMMAND>` nennt und etwas Falsches
|
|
786
|
+
# darueber sagt, laeuft durch. Die Pruefung faengt das Vergessen, nicht den Irrtum.
|
|
787
|
+
# ZWEITE GRENZE: Sie gilt nur fuer `sitzung`-Zellen. Ein `review` braucht keinen
|
|
788
|
+
# Messbaum, und ein `skript` fuehrt seine Befehle selbst.
|
|
789
|
+
P60_EXEC_RE = re.compile(r"Exec\((<[A-Z_]+_COMMAND>)\)")
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
def _skills_mit_befehlsschlitz(root: str) -> dict:
|
|
793
|
+
"""Skillname -> Liste der Befehlsschlitze, die sein Frontmatter ausfuehrt.
|
|
794
|
+
|
|
795
|
+
Abgeleitet aus den Skillquellen, nicht gepflegt: Wer einem Skill einen Befehl
|
|
796
|
+
hinzufuegt, soll nicht daran denken muessen, eine Liste im Validator nachzuziehen.
|
|
797
|
+
"""
|
|
798
|
+
raus = {}
|
|
799
|
+
basen = [os.path.join(root, KERN, "framework", "skills"),
|
|
800
|
+
os.path.join(root, KERN, "framework", "role-packs")]
|
|
801
|
+
for basis in basen:
|
|
802
|
+
if not os.path.isdir(basis):
|
|
803
|
+
continue
|
|
804
|
+
for wurzel, _, files in os.walk(basis):
|
|
805
|
+
if "SKILL.md" not in files:
|
|
806
|
+
continue
|
|
807
|
+
text = read(os.path.join(wurzel, "SKILL.md"))
|
|
808
|
+
if not text.startswith("---"):
|
|
809
|
+
continue
|
|
810
|
+
ende = text.find("---", 3)
|
|
811
|
+
if ende < 0:
|
|
812
|
+
continue
|
|
813
|
+
schlitze = sorted(set(P60_EXEC_RE.findall(text[3:ende])))
|
|
814
|
+
if schlitze:
|
|
815
|
+
raus[os.path.basename(wurzel)] = schlitze
|
|
816
|
+
return raus
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
def check_befehlsschlitz_in_vorbedingung(root: str) -> None:
|
|
820
|
+
"""Pruefung 60 (D-178): Der Ausloeser braucht einen Befehl - die Zelle sagt es."""
|
|
821
|
+
skills = _skills_mit_befehlsschlitz(root)
|
|
822
|
+
if not skills:
|
|
823
|
+
err(f"{KERN}/framework/skills/: kein Skill mit 'Exec(<..._COMMAND>)' im "
|
|
824
|
+
f"Frontmatter gefunden – Prüfung 60 leitet ihren Gegenstand daraus ab und "
|
|
825
|
+
f"hat ihn verloren; sie bestünde sonst leise (D-23)")
|
|
826
|
+
return
|
|
827
|
+
dateien = [os.path.join(root, KERN, "tests", "TEST_CATALOG.md")]
|
|
828
|
+
for basis in (os.path.join(root, KERN, "framework", "skills"),
|
|
829
|
+
os.path.join(root, KERN, "framework", "role-packs")):
|
|
830
|
+
for wurzel, _, files in os.walk(basis):
|
|
831
|
+
if "TESTS.md" in files:
|
|
832
|
+
dateien.append(os.path.join(wurzel, "TESTS.md"))
|
|
833
|
+
for pfad in sorted(dateien):
|
|
834
|
+
if not os.path.isfile(pfad):
|
|
835
|
+
continue
|
|
836
|
+
rel = os.path.relpath(pfad, root).replace(os.sep, "/")
|
|
837
|
+
i_vor = i_ein = i_pm = -1
|
|
838
|
+
for nr, zeile in enumerate(read(pfad).splitlines(), 1):
|
|
839
|
+
if not zeile.lstrip().startswith("|"):
|
|
840
|
+
continue
|
|
841
|
+
if "Prüfmethode" in zeile and "Eingabe" in zeile:
|
|
842
|
+
i_vor = _tabellenspalte(zeile, "Vorbedingung")
|
|
843
|
+
i_ein = _tabellenspalte(zeile, "Eingabe")
|
|
844
|
+
i_pm = _tabellenspalte(zeile, "Prüfmethode")
|
|
845
|
+
continue
|
|
846
|
+
if min(i_vor, i_ein, i_pm) < 0:
|
|
847
|
+
continue
|
|
848
|
+
zellen = [z.strip() for z in zeile.strip().strip("|").split("|")]
|
|
849
|
+
if len(zellen) <= max(i_vor, i_ein, i_pm):
|
|
850
|
+
continue
|
|
851
|
+
if "sitzung" not in zellen[i_pm]:
|
|
852
|
+
continue
|
|
853
|
+
ausloeser, vorbedingung = zellen[i_ein], zellen[i_vor]
|
|
854
|
+
gebraucht = []
|
|
855
|
+
for skill, schlitze in skills.items():
|
|
856
|
+
if f"/{skill}" in ausloeser:
|
|
857
|
+
gebraucht += schlitze
|
|
858
|
+
fehlend = sorted({s for s in gebraucht if s not in vorbedingung})
|
|
859
|
+
if fehlend:
|
|
860
|
+
err(f"{rel}:{nr}: Der Auslöser ruft einen Skill auf, der "
|
|
861
|
+
f"{', '.join(fehlend)} ausführt – die Vorbedingung nennt den "
|
|
862
|
+
f"Schlitz nicht. Steht der Befehl im Meßbaum im `ask`-Korb, hält "
|
|
863
|
+
f"der Lauf regelkonform an, und gemessen ist der Korb statt des "
|
|
864
|
+
f"Gegenstands (D-134, D-178)")
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
# --- Pruefung 59: Der Overlay-Wert in der Schicht, die ihn durchsetzt ---------------
|
|
868
|
+
#
|
|
869
|
+
# ANLASS. Gemessen am 2026-09-18 am Uebungsrepositorium (CR-2026-090, Befund 3): 0.63.0
|
|
870
|
+
# hat die Sperre von .github/** auf .github/workflows/** EINGEENGT, weil sie sonst die
|
|
871
|
+
# Merge-Request-Vorlage mitsperrt - einen Traeger, den fw-mr-description ausdruecklich
|
|
872
|
+
# als zulaessige Kontextquelle fuehrt (D-161). Die Einengung steht in
|
|
873
|
+
# .koolie/project-overlay/OVERLAY.md. Die beiden Traeger, die den Client WIRKLICH binden - die
|
|
874
|
+
# Laufzeitfassung des Overlays und der deny-Korb der Berechtigungsdatei - tragen
|
|
875
|
+
# weiterhin den alten, weiteren Wert. git log -S sagt: seit dem ersten Commit des
|
|
876
|
+
# Repositoriums unveraendert.
|
|
877
|
+
#
|
|
878
|
+
# DREI PRUEFUNGEN SAHEN ES NICHT, JEDE AUS EINEM EIGENEN GRUND. Pruefung 56 loest ueber
|
|
879
|
+
# die BINDUNGSZEILE DER QUELLE auf - sie liest genau den Traeger, der richtig ist.
|
|
880
|
+
# Pruefung 55b fragt, ob der Platzhalter GEBUNDEN ist, nicht welchen WERT er traegt; ihr
|
|
881
|
+
# eigener Kopfkommentar sagt seit 0.63.0 "Eine Bindung an den falschen Wert laeuft
|
|
882
|
+
# durch." Und --strict-overlay vergleicht Quelle und Laufzeitfassung allein im STATUS -
|
|
883
|
+
# der Abgleich der uebrigen Werte ist seit CR-2026-044 E4 offen.
|
|
884
|
+
#
|
|
885
|
+
# DREI GEGENSTAENDE:
|
|
886
|
+
# (a) Die Laufzeitfassung des Overlays NENNT <EXCLUDED_PATHS>. Ein Traeger, der den
|
|
887
|
+
# Wert nur einsetzt, ist fuer sich stimmig - und faellt niemandem auf. Das ist
|
|
888
|
+
# 55b eine Schicht tiefer.
|
|
889
|
+
# (b) Die Zeile, die ihn nennt, traegt DIESELBE Globmenge wie die Bindungszeile der
|
|
890
|
+
# Quelle. Abweichung in beide Richtungen ist ein Fehler; die Quelle ist massgeblich.
|
|
891
|
+
# (c) Jeder Glob der Quelle hat im deny-Korb eine Lese- UND eine Schreibsperre.
|
|
892
|
+
#
|
|
893
|
+
# GRENZE, UND SIE IST GENANNT. Geprueft wird EIN Platzhalter. <EXCLUDED_PATHS> ist der
|
|
894
|
+
# einzige, dessen Wert eine maschinell vergleichbare Gestalt hat - eine Globliste - und
|
|
895
|
+
# der zugleich zwei Schichten bindet. Das ist eine Enthaltung, keine Stille.
|
|
896
|
+
# ZWEITE GRENZE. (c) prueft nur die Richtung Quelle -> Korb. Ein ueberzaehliger Eintrag
|
|
897
|
+
# bleibt zulaessig - dasselbe Argument, mit dem Pruefung 42 die vier Pfadschlitze
|
|
898
|
+
# ausnimmt: dort ist Ueberzaehliges ohnehin erlaubt. Der gemessene Fall wird trotzdem
|
|
899
|
+
# gefangen, weil .github/workflows/** im Korb FEHLT.
|
|
900
|
+
P59_PLATZHALTER = "<EXCLUDED_PATHS>"
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
def _p59_globs(zellentext: list) -> list:
|
|
904
|
+
"""Die Globs einer Wertangabe - je Backtick-Token, an Kommas getrennt.
|
|
905
|
+
|
|
906
|
+
Die beiden uebernehmenden Projekte schreiben den Wert verschieden: eines als drei
|
|
907
|
+
Backtick-Token, das andere als eines mit Kommas darin. Wer nur das eine kennt,
|
|
908
|
+
vergleicht Zeichenketten statt Mengen.
|
|
909
|
+
"""
|
|
910
|
+
raus = []
|
|
911
|
+
for token in zellentext:
|
|
912
|
+
for teil in token.split(","):
|
|
913
|
+
t = teil.strip()
|
|
914
|
+
if t and t not in raus:
|
|
915
|
+
raus.append(t)
|
|
916
|
+
return raus
|
|
917
|
+
|
|
918
|
+
|
|
919
|
+
def check_overlay_wertabgleich(root: str, man: dict) -> None:
|
|
920
|
+
"""Pruefung 59 (D-171): Der Overlay-Wert gilt in der Schicht, die ihn durchsetzt."""
|
|
921
|
+
overlay_pfad = os.path.join(root, ".koolie/project-overlay", "OVERLAY.md")
|
|
922
|
+
if not os.path.isfile(overlay_pfad):
|
|
923
|
+
return # Kandidatenphase - dieselbe Enthaltung wie Pruefung 42
|
|
924
|
+
quelle = _p59_globs(_p56_ausgeschlossen(read(overlay_pfad)))
|
|
925
|
+
if not quelle or any(TBD_RE.search(g) for g in quelle):
|
|
926
|
+
return # noch nicht ausgefuellt - das meldet --check-overlay-ready
|
|
927
|
+
rel_rt = f"{man['pack_runtime_dir']}/{regeldatei(man, '20-project-overlay.md')}"
|
|
928
|
+
runtime_pfad = os.path.join(root, *rel_rt.split("/"))
|
|
929
|
+
if os.path.isfile(runtime_pfad):
|
|
930
|
+
text = read(runtime_pfad)
|
|
931
|
+
zeilen = [z for z in text.split("\n") if P59_PLATZHALTER in z]
|
|
932
|
+
if not zeilen:
|
|
933
|
+
err(f"{rel_rt}: nennt {P59_PLATZHALTER} nicht. Die Laufzeitfassung setzt den "
|
|
934
|
+
f"Wert damit ein, statt den Platzhalter zu binden – sie ist für sich "
|
|
935
|
+
f"stimmig, und niemand sieht, ob ihr Wert noch der des Quell-Overlays "
|
|
936
|
+
f"ist. Genau so hat eine Einengung aus 0.63.0 die Schicht nie erreicht, "
|
|
937
|
+
f"die sie durchsetzt (D-171)")
|
|
938
|
+
elif not TBD_RE.search(zeilen[0]):
|
|
939
|
+
# Ein Ausfuellschlitz in der Laufzeitfassung ist Sache von --strict-overlay,
|
|
940
|
+
# das ihn schon meldet - zwei Meldungen fuer einen Zustand sind eine zuviel.
|
|
941
|
+
ist = _p59_globs([t for t in re.findall(r"`([^`]+)`", zeilen[0])
|
|
942
|
+
if t != P59_PLATZHALTER])
|
|
943
|
+
fehlt = [g for g in quelle if g not in ist]
|
|
944
|
+
zuviel = [g for g in ist if g not in quelle]
|
|
945
|
+
if fehlt or zuviel:
|
|
946
|
+
err(f"{rel_rt}: die ausgeschlossenen Pfade weichen vom Quell-Overlay ab – "
|
|
947
|
+
f"dort fehlend: {', '.join(fehlt) or 'keine'}; dort nicht vorgesehen: "
|
|
948
|
+
f"{', '.join(zuviel) or 'keine'}. Maßgeblich ist "
|
|
949
|
+
f".koolie/project-overlay/OVERLAY.md; die Laufzeitfassung ist die Schicht, die "
|
|
950
|
+
f"der Client lädt (D-171)")
|
|
951
|
+
# Gegenstand (c) liest den deny-Korb einer JSON-Datei. Bis 1.4.4 stand er nicht in
|
|
952
|
+
# FORMATGEBUNDENE_PRUEFUNGEN und kehrte bei einem Pack mit TOML an json.loads still
|
|
953
|
+
# zurueck - gemessen mit CR-2026-138 an einer Wegwerf-Installation von openai-codex:
|
|
954
|
+
# <EXCLUDED_PATHS> in Quelle und Laufzeitfassung gefuellt, in der Berechtigungsdatei
|
|
955
|
+
# keine Sperre, und diese Pruefung meldete nichts. Die Luecke ist dieselbe; sie ist
|
|
956
|
+
# jetzt erklaert (D-346) statt verschwiegen.
|
|
957
|
+
if formatgebunden(man, 59):
|
|
958
|
+
return
|
|
959
|
+
rel_perm = man["permissions_file"]
|
|
960
|
+
perm_pfad = os.path.join(root, *rel_perm.split("/"))
|
|
961
|
+
if not os.path.isfile(perm_pfad):
|
|
962
|
+
return
|
|
963
|
+
try:
|
|
964
|
+
cfg = json.loads(read(perm_pfad))
|
|
965
|
+
except json.JSONDecodeError:
|
|
966
|
+
return # check_config hat das bereits gemeldet
|
|
967
|
+
deny = [r for r in cfg.get("permissions", {}).get("deny", []) if isinstance(r, str)]
|
|
968
|
+
if any(P59_PLATZHALTER in r for r in deny):
|
|
969
|
+
return # Schlitz noch ungefuellt - das ist Sache von --check-overlay-ready
|
|
970
|
+
praefix = man.get("permission_path_prefix", "")
|
|
971
|
+
werkzeuge = man.get("permission_tools", {})
|
|
972
|
+
for art in ("read", "write"):
|
|
973
|
+
for werkzeug in werkzeuge.get(art, ()):
|
|
974
|
+
for glob in quelle:
|
|
975
|
+
if any(f"{werkzeug}({p}{glob})" in deny for p in ("", praefix)):
|
|
976
|
+
continue
|
|
977
|
+
err(f"{rel_perm}: der ausgeschlossene Pfad `{glob}` des Quell-Overlays hat "
|
|
978
|
+
f"keine Regel {werkzeug}({glob}) im deny-Korb. Die Berechtigungsdatei "
|
|
979
|
+
f"ist die Schicht, die technisch sperrt – ein Wert, der nur im Overlay "
|
|
980
|
+
f"steht, sperrt nichts (D-171)")
|
|
981
|
+
|
|
982
|
+
|
|
983
|
+
# --- Pruefung 89: die uebrigen Pfadplatzhalter in den Schichten, die sie tragen ------
|
|
984
|
+
#
|
|
985
|
+
# ANLASS (K-69, CR-2026-136 E4, CR-2026-138 E6). Pruefung 59 vergleicht EINEN
|
|
986
|
+
# Pfadplatzhalter. <ALLOWED_PATHS>, <TEST_PATHS>, <DOC_PATHS> und <READ_ONLY_PATHS> haben
|
|
987
|
+
# dieselbe Gestalt - eine Globliste - und waren ungeprueft, nicht geprueft-und-gut:
|
|
988
|
+
# Gezaehlt am 2026-09-18 wich von sechs Werten des Uebungs-Overlays einer ab. Weil
|
|
989
|
+
# Laufzeitfassung und Berechtigungsdatei Saat bleiben (D-353), faengt nur eine Pruefung
|
|
990
|
+
# die Handpflege an drei Stellen auf.
|
|
991
|
+
#
|
|
992
|
+
# DREI GEGENSTAENDE, dieselben wie bei 59:
|
|
993
|
+
# (a) Die Laufzeitfassung NENNT jeden der vier Platzhalter. Ein Traeger, der den Wert
|
|
994
|
+
# nur einsetzt, ist fuer sich stimmig - und niemand sieht, ob sein Wert noch der
|
|
995
|
+
# der Quelle ist (D-160).
|
|
996
|
+
# (b) Der Wert hinter dem Platzhalter ist dieselbe Menge wie in der Quelle.
|
|
997
|
+
# (c) Jeder Nur-Lese-Pfad hat im deny-Korb eine Schreibsperre. Seit 1.5.0 fuehrt die
|
|
998
|
+
# Kernquelle den Schlitz dafuer (D-356); bis dahin trugen beide uebernehmenden
|
|
999
|
+
# Projekte die Sperre von Hand - auf dieselbe Weise.
|
|
1000
|
+
# Seit 1.20.1 ebenso jeder Glob von <CI_CONFIG_PATHS> und
|
|
1001
|
+
# <QUALITY_GATE_CONFIG_PATHS> (CR-2026-163, D-493, K-35). Beide stehen nur im
|
|
1002
|
+
# deny-Korb, und ein zu ENG gefuellter Schlitz ist eine stille Lockerung.
|
|
1003
|
+
# "Deckungsgleich" heisst: Jeder Glob der Quelle hat seine eigene Regel - so
|
|
1004
|
+
# entfaltet install.py den Schlitz auch. Die Laufzeitfassung fuehrt die beiden
|
|
1005
|
+
# nicht; (a) und (b) gelten fuer sie deshalb nicht.
|
|
1006
|
+
#
|
|
1007
|
+
# DIE QUELLE IST DIE DREISPALTIGE ZEILE VON ABSCHNITT 4, gefunden ueber die
|
|
1008
|
+
# Platzhalterzelle. Ein Overlay, das anders bindet, ENTGEHT der Pruefung nicht still: Es
|
|
1009
|
+
# bekommt eine eigene Meldung (CR-2026-136 E4, "melden, nicht verschweigen").
|
|
1010
|
+
#
|
|
1011
|
+
# "KEIN WERT" HAT MEHRERE SCHREIBWEISEN, und sie sind gemessen: Der Pilot fuehrt fuer
|
|
1012
|
+
# <DOC_PATHS> in der Quelle `nicht vorhanden`, in der Laufzeitfassung `keine`. Beides
|
|
1013
|
+
# ist die leere Menge; wer Zeichenketten vergleicht, meldet einen Unterschied, den es
|
|
1014
|
+
# nicht gibt.
|
|
1015
|
+
#
|
|
1016
|
+
# GRENZE. Der Wert in der Laufzeitfassung endet am ersten " · " oder " – " der Zeile;
|
|
1017
|
+
# was danach steht ("zusaetzlich immer ...") ist Erlaeuterung und gehoert nicht zur
|
|
1018
|
+
# Menge. Und (c) prueft wie 59 nur die Richtung Quelle -> Korb.
|
|
1019
|
+
P89_PLATZHALTER = ("<ALLOWED_PATHS>", "<TEST_PATHS>", "<DOC_PATHS>", "<READ_ONLY_PATHS>")
|
|
1020
|
+
P89_SPERRPLATZHALTER = ("<READ_ONLY_PATHS>", "<CI_CONFIG_PATHS>", "<QUALITY_GATE_CONFIG_PATHS>")
|
|
1021
|
+
P89_KEIN_WERT = {"nicht vorhanden", "keine", "keiner", "kein", "–", "-"}
|
|
1022
|
+
|
|
1023
|
+
|
|
1024
|
+
def _p89_menge(werte: list) -> list:
|
|
1025
|
+
"""Die Globs einer Wertangabe ohne die Schreibweisen fuer "kein Wert"."""
|
|
1026
|
+
return [g for g in _p59_globs(werte) if g.lower() not in P89_KEIN_WERT]
|
|
1027
|
+
|
|
1028
|
+
|
|
1029
|
+
def _p89_quelle(text: str, platzhalter: str):
|
|
1030
|
+
"""(Zeile gefunden, Werte oder None bei Ausfuellschlitz) aus Abschnitt 4 des Overlays."""
|
|
1031
|
+
for zeile in text.replace("\r\n", "\n").split("\n"):
|
|
1032
|
+
zellen = tabellenzellen(zeile.strip())
|
|
1033
|
+
for i, zelle in enumerate(zellen[:-1]):
|
|
1034
|
+
if zelle.strip() != f"`{platzhalter}`":
|
|
1035
|
+
continue
|
|
1036
|
+
wert = zellen[i + 1]
|
|
1037
|
+
if TBD_RE.search(wert):
|
|
1038
|
+
return True, None
|
|
1039
|
+
treffer = re.findall(r"`([^`]+)`", wert)
|
|
1040
|
+
return True, _p89_menge(treffer or [wert.strip()])
|
|
1041
|
+
return False, None
|
|
1042
|
+
|
|
1043
|
+
|
|
1044
|
+
def _p89_laufzeit(text: str, platzhalter: str):
|
|
1045
|
+
"""(Zeile gefunden, Werte oder None bei Ausfuellschlitz) aus der Laufzeitfassung."""
|
|
1046
|
+
token = f"`{platzhalter}`"
|
|
1047
|
+
for zeile in text.replace("\r\n", "\n").split("\n"):
|
|
1048
|
+
if token not in zeile:
|
|
1049
|
+
continue
|
|
1050
|
+
rest = zeile.split(token, 1)[1].lstrip(")").lstrip(":").strip()
|
|
1051
|
+
rest = re.split(r" · | – ", rest, maxsplit=1)[0]
|
|
1052
|
+
if TBD_RE.search(rest):
|
|
1053
|
+
return True, None
|
|
1054
|
+
treffer = [t for t in re.findall(r"`([^`]+)`", rest)
|
|
1055
|
+
if not PROJEKTPLATZHALTER.fullmatch(t)]
|
|
1056
|
+
return True, _p89_menge(treffer or [rest.strip().rstrip(".")])
|
|
1057
|
+
return False, None
|
|
1058
|
+
|
|
1059
|
+
|
|
1060
|
+
def check_overlay_pfadabgleich(root: str, man: dict) -> None:
|
|
1061
|
+
"""Pruefung 89 (K-69, D-357): die vier uebrigen Pfadplatzhalter in allen Schichten."""
|
|
1062
|
+
overlay_pfad = os.path.join(root, ".koolie/project-overlay", "OVERLAY.md")
|
|
1063
|
+
if not os.path.isfile(overlay_pfad):
|
|
1064
|
+
return # Kandidatenphase - dieselbe Enthaltung wie Pruefung 59
|
|
1065
|
+
quelltext = read(overlay_pfad)
|
|
1066
|
+
rel_rt = f"{man['pack_runtime_dir']}/{regeldatei(man, '20-project-overlay.md')}"
|
|
1067
|
+
runtime_pfad = os.path.join(root, *rel_rt.split("/"))
|
|
1068
|
+
laufzeit = read(runtime_pfad) if os.path.isfile(runtime_pfad) else None
|
|
1069
|
+
sperren: dict = {}
|
|
1070
|
+
for platzhalter in P89_PLATZHALTER:
|
|
1071
|
+
da, quelle = _p89_quelle(quelltext, platzhalter)
|
|
1072
|
+
if not da:
|
|
1073
|
+
err(f".koolie/project-overlay/OVERLAY.md: keine Zeile mit der Platzhalterzelle "
|
|
1074
|
+
f"`{platzhalter}` in Abschnitt 4. Prüfung 89 liest den Wert aus der "
|
|
1075
|
+
f"dreispaltigen Zeile der Vorlage; ein Overlay, das anders bindet, wird "
|
|
1076
|
+
f"gemeldet und nicht übergangen (K-69, CR-2026-136 E4)")
|
|
1077
|
+
continue
|
|
1078
|
+
if quelle is None:
|
|
1079
|
+
continue # noch nicht ausgefuellt - das meldet --check-overlay-ready
|
|
1080
|
+
if platzhalter == "<READ_ONLY_PATHS>":
|
|
1081
|
+
sperren[platzhalter] = quelle
|
|
1082
|
+
if laufzeit is None:
|
|
1083
|
+
continue
|
|
1084
|
+
da, ist = _p89_laufzeit(laufzeit, platzhalter)
|
|
1085
|
+
if not da:
|
|
1086
|
+
err(f"{rel_rt}: nennt {platzhalter} nicht. Die Laufzeitfassung setzt den Wert "
|
|
1087
|
+
f"damit ein, statt den Platzhalter zu binden – sie ist für sich stimmig, und "
|
|
1088
|
+
f"niemand sieht, ob ihr Wert noch der des Quell-Overlays ist (D-160, K-69)")
|
|
1089
|
+
continue
|
|
1090
|
+
if ist is None:
|
|
1091
|
+
continue # Ausfuellschlitz in der Laufzeitfassung - Sache von --strict-overlay
|
|
1092
|
+
fehlt = [g for g in quelle if g not in ist]
|
|
1093
|
+
zuviel = [g for g in ist if g not in quelle]
|
|
1094
|
+
if fehlt or zuviel:
|
|
1095
|
+
err(f"{rel_rt}: der Wert von {platzhalter} weicht vom Quell-Overlay ab – dort "
|
|
1096
|
+
f"fehlend: {', '.join(fehlt) or 'keine'}; dort nicht vorgesehen: "
|
|
1097
|
+
f"{', '.join(zuviel) or 'keine'}. Maßgeblich ist "
|
|
1098
|
+
f".koolie/project-overlay/OVERLAY.md (K-69)")
|
|
1099
|
+
for platzhalter in P89_SPERRPLATZHALTER[1:]:
|
|
1100
|
+
da, quelle = _p89_quelle(quelltext, platzhalter)
|
|
1101
|
+
if da and quelle:
|
|
1102
|
+
sperren[platzhalter] = quelle # fehlende Zeile: dasselbe Schweigen wie --strict
|
|
1103
|
+
if not sperren or formatgebunden(man, 89):
|
|
1104
|
+
return
|
|
1105
|
+
rel_perm = man["permissions_file"]
|
|
1106
|
+
perm_pfad = os.path.join(root, *rel_perm.split("/"))
|
|
1107
|
+
if not os.path.isfile(perm_pfad):
|
|
1108
|
+
return
|
|
1109
|
+
try:
|
|
1110
|
+
cfg = json.loads(read(perm_pfad))
|
|
1111
|
+
except json.JSONDecodeError:
|
|
1112
|
+
return # check_config hat das bereits gemeldet
|
|
1113
|
+
deny = [r for r in cfg.get("permissions", {}).get("deny", []) if isinstance(r, str)]
|
|
1114
|
+
praefix = man.get("permission_path_prefix", "")
|
|
1115
|
+
for platzhalter, globs in sperren.items():
|
|
1116
|
+
if any(platzhalter in r for r in deny):
|
|
1117
|
+
continue # Schlitz noch ungefuellt - das ist Sache von --strict-overlay
|
|
1118
|
+
for werkzeug in man.get("permission_tools", {}).get("write", ()):
|
|
1119
|
+
for glob in globs:
|
|
1120
|
+
if any(f"{werkzeug}({p}{glob})" in deny for p in ("", praefix)):
|
|
1121
|
+
continue
|
|
1122
|
+
if platzhalter == "<READ_ONLY_PATHS>":
|
|
1123
|
+
err(f"{rel_perm}: der Nur-Lese-Pfad `{glob}` des Quell-Overlays hat keine "
|
|
1124
|
+
f"Regel {werkzeug}({glob}) im deny-Korb. Ein Integritätsschutz, der nur "
|
|
1125
|
+
f"im Overlay steht, sperrt nichts (K-69, D-356)")
|
|
1126
|
+
else:
|
|
1127
|
+
err(f"{rel_perm}: der Pfad `{glob}` aus {platzhalter} des Quell-Overlays "
|
|
1128
|
+
f"hat keine Regel {werkzeug}({glob}) im deny-Korb. Ein zu eng "
|
|
1129
|
+
f"gefüllter Schlitz ist eine stille Lockerung (K-35, D-493)")
|
|
1130
|
+
|
|
1131
|
+
# --- Pruefung 110: die aktivierten Packs gegen die Regelablage (CR-2026-164, D-504, K-44)
|
|
1132
|
+
#
|
|
1133
|
+
# ANLASS, GEGENGEPRUEFT (2026-09-17, CR-2026-076 Abschnitt 6.3): Das Overlay des
|
|
1134
|
+
# Uebungsrepositoriums fuehrt zwei Role Packs und zwei Technology Packs als aktiviert. Vier
|
|
1135
|
+
# Regeldateien und zwei Skills entfernt - --strict-overlay meldete vorher wie nachher
|
|
1136
|
+
# dasselbe. Ein Projekt verlor so seine Ebenen 5 und 6 still: durch einen Packwechsel, einen
|
|
1137
|
+
# verunglueckten Lauf von --update oder ein Versehen. Aufgefallen war es dem KI-Client, nicht dem
|
|
1138
|
+
# Pruefapparat.
|
|
1139
|
+
#
|
|
1140
|
+
# GEPRUEFT (nur --strict-overlay): Die Zeilen 'Aktivierte Role Packs' und 'Aktivierte
|
|
1141
|
+
# Technology Packs' des Overlays gegen die Laufzeitfassungen 30-role-<pack> und
|
|
1142
|
+
# 40-tech-<pack> der Regelablage, in beide Richtungen. Ein Pack gilt als genannt, wenn sein
|
|
1143
|
+
# Name in Backticks in der Wertzelle steht ('tech-' davor ist erlaubt); `keine` heisst
|
|
1144
|
+
# keines. Eine Zeile, die noch `<TBD…>` traegt, wird nicht gelesen.
|
|
1145
|
+
# FEHLER: ein genanntes Pack ohne Laufzeitfassung und eine Laufzeitfassung ohne Nennung.
|
|
1146
|
+
# WARNUNG: Laufzeitfassungen, aber keine Zeile - die Vorlage fuehrt die Zeile fuer Role
|
|
1147
|
+
# Packs erst seit 1.20.2.
|
|
1148
|
+
# GRENZE: die Laufzeitfassung, nicht die Skills eines Packs (die haelt Pruefung 72 gegen
|
|
1149
|
+
# die Berechtigungen); die Nennung, nicht die Version.
|
|
1150
|
+
P110_ZEILEN = (("Aktivierte Role Packs", "30-role-"), ("Aktivierte Technology Packs", "40-tech-"))
|
|
1151
|
+
P110_NAME_RE = re.compile(r"`([a-z0-9][a-z0-9-]*)`")
|
|
1152
|
+
|
|
1153
|
+
|
|
1154
|
+
def _p110_genannt(text: str, beschriftung: str):
|
|
1155
|
+
"""(Zeile vorhanden?, genannte Packs oder None bei `<TBD…>`)."""
|
|
1156
|
+
m = re.search(r"^\|\s*" + re.escape(beschriftung) + r"[^|]*\|([^|\n]*)\|", text, re.M)
|
|
1157
|
+
if not m:
|
|
1158
|
+
return False, None
|
|
1159
|
+
zelle = m.group(1)
|
|
1160
|
+
if TBD_RE.search(zelle):
|
|
1161
|
+
return True, None
|
|
1162
|
+
namen = {n[len("tech-"):] if n.startswith("tech-") else n
|
|
1163
|
+
for n in P110_NAME_RE.findall(zelle)}
|
|
1164
|
+
return True, namen - {"keine"}
|
|
1165
|
+
|
|
1166
|
+
|
|
1167
|
+
def check_aktivierte_packs(root: str, man: dict) -> None:
|
|
1168
|
+
"""Pruefung 110 (D-504, K-44): Was das Overlay als aktiviert fuehrt, liegt in der Regelablage."""
|
|
1169
|
+
overlay_pfad = os.path.join(root, ".koolie/project-overlay", "OVERLAY.md")
|
|
1170
|
+
ablage = os.path.join(root, *man["pack_runtime_dir"].split("/"))
|
|
1171
|
+
if not os.path.isfile(overlay_pfad) or not os.path.isdir(ablage):
|
|
1172
|
+
return
|
|
1173
|
+
text = read(overlay_pfad)
|
|
1174
|
+
endung = regeldatei(man, "x.md")[1:]
|
|
1175
|
+
dateien = [f for f in os.listdir(ablage) if f.endswith(endung)]
|
|
1176
|
+
for beschriftung, praefix in P110_ZEILEN:
|
|
1177
|
+
da = {f[len(praefix):-len(endung)] for f in dateien if f.startswith(praefix)}
|
|
1178
|
+
zeile, genannt = _p110_genannt(text, beschriftung)
|
|
1179
|
+
if not zeile:
|
|
1180
|
+
if da:
|
|
1181
|
+
warn(f".koolie/project-overlay/OVERLAY.md: keine Zeile '{beschriftung}', aber "
|
|
1182
|
+
f"{len(da)} Laufzeitfassung(en) {praefix}* in {man['pack_runtime_dir']}/ - "
|
|
1183
|
+
f"welches Pack aktiviert ist, entscheidet das Overlay (K-44)")
|
|
1184
|
+
continue
|
|
1185
|
+
if genannt is None:
|
|
1186
|
+
continue
|
|
1187
|
+
for pack in sorted(genannt - da):
|
|
1188
|
+
err(f".koolie/project-overlay/OVERLAY.md: führt '{pack}' unter '{beschriftung}', "
|
|
1189
|
+
f"aber {man['pack_runtime_dir']}/{praefix}{pack}{endung} fehlt - die Ebene "
|
|
1190
|
+
f"dieses Packs lädt in keiner Sitzung (K-44)")
|
|
1191
|
+
for pack in sorted(da - genannt):
|
|
1192
|
+
err(f"{man['pack_runtime_dir']}/{praefix}{pack}{endung}: lädt in jeder passenden "
|
|
1193
|
+
f"Sitzung, aber das Overlay führt '{pack}' nicht unter '{beschriftung}' - "
|
|
1194
|
+
f"aktiviert wird ein Pack im Overlay (K-44)")
|
|
1195
|
+
|
|
1196
|
+
|
|
1197
|
+
# --- Pruefung 111: fremde Skills, deklariert (CR-2026-167, D-514, K-31) ----------------
|
|
1198
|
+
#
|
|
1199
|
+
# ANLASS, GEMESSEN (2026-09-30): OpenSpec 1.13.2 und GitHub Spec Kit legen ihre Skills in
|
|
1200
|
+
# dieselbe Laufzeitablage wie Koolie (.claude/skills/openspec-*, speckit-*). Der Validator
|
|
1201
|
+
# prueft jeden Skill dort nach den Regeln fuer Koolie-Skills - sechs OpenSpec-Skills ergaben
|
|
1202
|
+
# 60 Fehler und 18 Warnungen, in einem Projekt, in dem beide Rahmenwerke einander keine
|
|
1203
|
+
# Datei aendern. Seither deklariert das Projekt sie im Overlay-Manifest
|
|
1204
|
+
# ('fremde_skills: openspec-, speckit-'), und Pruefung 5 nimmt sie aus.
|
|
1205
|
+
#
|
|
1206
|
+
# GEPRUEFT: FEHLER, wenn ein deklariertes Praefix einen Koolie-Skill treffen koennte (fw-,
|
|
1207
|
+
# prj-, role-, tech-, oder kuerzer als drei Zeichen) - die Deklaration waere sonst ein Weg,
|
|
1208
|
+
# die eigenen Skills der Pruefung zu entziehen; ein solches Praefix nimmt nichts aus.
|
|
1209
|
+
# WARNUNG, wenn ein Praefix keinen Skill der Laufzeitablage trifft (Deklaration ohne
|
|
1210
|
+
# Gegenstand), wenn koexistenz.py ein bekanntes fremdes Rahmenwerk mit Skills erkennt,
|
|
1211
|
+
# deren Praefix nicht deklariert ist, und wenn die Wurzel-Anweisung den markierten Block
|
|
1212
|
+
# eines fremden Generators traegt - er zaehlt ins Budget (Pruefung 4, K-185), und die
|
|
1213
|
+
# naechste Aktualisierung bricht davor ab (D-515).
|
|
1214
|
+
# GRENZE: die Deklaration und die Ablage, nicht der Inhalt eines fremden Skills. Den Korb
|
|
1215
|
+
# der Berechtigungsdatei verlangt Pruefung 72 weiter (D-238); was ein fremder Skill tut,
|
|
1216
|
+
# prueft Koolie nicht - das ist die Abgrenzung nach Gegenstand (D-478).
|
|
1217
|
+
def check_fremde_skills(root: str, man: dict) -> None:
|
|
1218
|
+
"""Pruefung 111 (D-514, K-31): deklarierte fremde Skills - zulaessig und mit Gegenstand."""
|
|
1219
|
+
manifest = os.path.join(root, ".koolie", "project-overlay", "overlay-manifest.yaml")
|
|
1220
|
+
if not os.path.isfile(manifest):
|
|
1221
|
+
return
|
|
1222
|
+
fremde_praefixe(root) # legt den Kern in den Suchpfad
|
|
1223
|
+
try:
|
|
1224
|
+
import koexistenz
|
|
1225
|
+
except ImportError:
|
|
1226
|
+
return
|
|
1227
|
+
wurzel = man.get("root_instruction_file", "")
|
|
1228
|
+
wurzel_pfad = os.path.join(root, *wurzel.split("/")) if wurzel else ""
|
|
1229
|
+
if wurzel_pfad and os.path.isfile(wurzel_pfad):
|
|
1230
|
+
for name, zeichen in koexistenz.markierte_bloecke(read(wurzel_pfad)):
|
|
1231
|
+
warn(f"{wurzel}: traegt den markierten Block '{name}' eines fremden Generators "
|
|
1232
|
+
f"({zeichen} Zeichen) - er zaehlt ins Budget der stets geladenen Texte "
|
|
1233
|
+
f"(K-185), und install.py --update bricht davor ab (D-515)")
|
|
1234
|
+
ablage = os.path.join(root, *man["skills_dir"].split("/"))
|
|
1235
|
+
skills = sorted(os.listdir(ablage)) if os.path.isdir(ablage) else []
|
|
1236
|
+
deklariert = koexistenz.deklariert(root)
|
|
1237
|
+
rel = ".koolie/project-overlay/overlay-manifest.yaml"
|
|
1238
|
+
for p in deklariert:
|
|
1239
|
+
if not koexistenz.zulaessig(p):
|
|
1240
|
+
err(f"{rel}: fremde_skills nennt '{p}' - das Praefix koennte einen Koolie-Skill "
|
|
1241
|
+
f"treffen (fw-, prj-, role-, tech-) und nimmt deshalb nichts aus (D-514)")
|
|
1242
|
+
elif not any(s.startswith(p) for s in skills):
|
|
1243
|
+
warn(f"{rel}: fremde_skills nennt '{p}', aber kein Skill in {man['skills_dir']}/ "
|
|
1244
|
+
f"beginnt damit - eine Deklaration ohne Gegenstand (D-514)")
|
|
1245
|
+
for b in koexistenz.erkennen(root, man["skills_dir"]):
|
|
1246
|
+
offen = [s for s in b["skills"] if not koexistenz.ist_deklariert(s, deklariert)]
|
|
1247
|
+
if b["name"] != "unbekannt" and offen:
|
|
1248
|
+
warn(f"{man['skills_dir']}/: {len(offen)} Skill(s) von {b['name']} "
|
|
1249
|
+
f"({b['praefix']}*) sind nicht deklariert - im Overlay-Manifest "
|
|
1250
|
+
f"'fremde_skills: {b['praefix']}' eintragen, sonst prueft Pruefung 5 sie als "
|
|
1251
|
+
f"Koolie-Skills (K-31, D-514)")
|