@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,1262 @@
|
|
|
1
|
+
"""Die Dokumente: Steuerzeichen, Altname, Dokumentstand und -zahlen, Lizenz,
|
|
2
|
+
Gegenzeichnung, Zeilenendeform, Bestandsliste, Chronikspanne, Zielangabe,
|
|
3
|
+
Rechtschreibung, Form und Steckbrief.
|
|
4
|
+
|
|
5
|
+
Pruefungen 66, 75, 77, 78, 79, 80, 81, 82, 83, 85, 92, 93 und 94. Teil des Validators
|
|
6
|
+
validate-framework.py, seit 1.19.1 nach Gegenstand in Module geteilt (K-174). Das
|
|
7
|
+
Register aller Pruefungen steht im Kopfkommentar des Einstiegs, die Grenze jeder
|
|
8
|
+
einzelnen in ihrem Kopfkommentar hier."""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import re
|
|
13
|
+
import subprocess
|
|
14
|
+
|
|
15
|
+
from .gemeinsam import (
|
|
16
|
+
_git_pfade, _verfolgte_dateien, DOK_WURZEL, err, hinweis, ist_quellrepositorium,
|
|
17
|
+
iter_text_files, KERN, nicht_geliefert, QUELLREPO_KENNZEICHEN, read,
|
|
18
|
+
REGISTER_ANKER, REGISTER_ENDE, tabellenzellen, TBD_RE, TEXT_EXT, warn)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# --- Pruefung 66: das verirrte Steuerzeichen ---------------------------------------
|
|
22
|
+
#
|
|
23
|
+
# GEGENSTAND ist ein Wagenruecklauf, dem kein Zeilenvorschub folgt. Er rendert nicht,
|
|
24
|
+
# er druckt nicht, und keine Leseroutine dieses Apparats gibt ihn heraus.
|
|
25
|
+
#
|
|
26
|
+
# 🔴 WARUM ER TROTZDEM ETWAS KAPUTT MACHT (D-217, CR-2026-107): git stuft einen
|
|
27
|
+
# Traeger mit einem einzelnen CR als BINAER ein und normalisiert seine Zeilenenden
|
|
28
|
+
# deshalb NICHT - weder ueber core.autocrlf noch ueber ein text=auto in einer
|
|
29
|
+
# .gitattributes. Gemessen am 2026-09-20 in einem eigens dafuer gebauten
|
|
30
|
+
# Repositorium, beide Faelle nebeneinander: Die Datei ohne verirrtes CR liegt danach
|
|
31
|
+
# als LF im Blob, die mit ihm unveraendert als CRLF.
|
|
32
|
+
# ➡️ DIE REGEL FUER ZEILENENDEN GREIFT BEI GENAU DEN DATEIEN NICHT, DIE SIE BRAUCHEN.
|
|
33
|
+
# Im Bestand war die Deckung vollstaendig: 14 Traeger mit verirrtem CR und 14 Traeger,
|
|
34
|
+
# deren Blob git nicht normalisiert hat - dieselben 14 von 440 Texttraegern.
|
|
35
|
+
#
|
|
36
|
+
# 🔴 UND KEINE DER 65 AELTEREN PRUEFUNGEN KONNTE ES SEHEN. `read` oeffnet im
|
|
37
|
+
# Universal-Newline-Modus; dort ist jedes CR bereits ein Zeilenvorschub, bevor eine
|
|
38
|
+
# Pruefung es zu Gesicht bekommt. Diese liest deshalb Bytes. Eine Pruefung, die ihren
|
|
39
|
+
# Gegenstand an der eigenen Leseroutine verliert, ist die stillste Bauform von D-23.
|
|
40
|
+
VERIRRTES_CR = re.compile(bytes([13]) + b'(?!' + bytes([10]) + b')')
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def check_verirrtes_steuerzeichen(root: str) -> None:
|
|
44
|
+
"""Pruefung 66 (D-217): Kein Textraeger traegt ein CR ohne folgenden LF."""
|
|
45
|
+
geprueft = 0
|
|
46
|
+
for path in iter_text_files(root):
|
|
47
|
+
try:
|
|
48
|
+
with open(path, "rb") as fh:
|
|
49
|
+
roh = fh.read()
|
|
50
|
+
except OSError:
|
|
51
|
+
continue
|
|
52
|
+
if b"\x00" in roh[:8000]:
|
|
53
|
+
continue
|
|
54
|
+
geprueft += 1
|
|
55
|
+
treffer = VERIRRTES_CR.findall(roh)
|
|
56
|
+
if not treffer:
|
|
57
|
+
continue
|
|
58
|
+
rel = os.path.relpath(path, root).replace(os.sep, "/")
|
|
59
|
+
stelle = VERIRRTES_CR.search(roh).start()
|
|
60
|
+
err(f"{rel}: {len(treffer)} verirrte(s) Steuerzeichen - Wagenrücklauf ohne "
|
|
61
|
+
f"folgenden Zeilenvorschub, das erste an Byte {stelle}. Es ist unsichtbar "
|
|
62
|
+
f"und nimmt git die Normalisierung: Ein solcher Träger gilt als binär, "
|
|
63
|
+
f"landet unverändert im Repositorium und lässt den nächsten Commit die "
|
|
64
|
+
f"ganze Datei neu schreiben (D-217)")
|
|
65
|
+
if not geprueft:
|
|
66
|
+
err(f"{KERN}/: keine einzige Textdatei gelesen – Prüfung 66 hat ihren "
|
|
67
|
+
f"Gegenstand verloren und bestünde sonst leise (D-23)")
|
|
68
|
+
|
|
69
|
+
# --- Pruefung 75: Kein Restbestand des alten Namens ---------------------------------
|
|
70
|
+
#
|
|
71
|
+
# ANLASS (D-271, CR-2026-119 E3). Mit 0.88.0 heisst das Framework Koolie und der Kern
|
|
72
|
+
# liegt unter .koolie/core. Ohne eine Pruefung ist "der Name ist weg" eine BEHAUPTUNG
|
|
73
|
+
# ohne Pruefung - und genau das ist der wiederkehrende Befundtyp dieses Repositoriums.
|
|
74
|
+
#
|
|
75
|
+
# ZAEHLBEREICH, UND ER HAENGT DAVON AB, WESSEN BESTAND GEPRUEFT WIRD.
|
|
76
|
+
#
|
|
77
|
+
# * Im FRAMEWORK-REPOSITORIUM: jeder verfolgte Traeger. Das ist die Lehre von D-295 -
|
|
78
|
+
# der Zaehlbereich von Kriterium 1 war kleiner als die Wirkungsflaeche, und wer nur
|
|
79
|
+
# den Kern sweept, laesst die Form in der Wurzel-README stehen.
|
|
80
|
+
# * In einem UEBERNEHMENDEN PROJEKT: nur, was das Framework AUSLIEFERT - der Kern und
|
|
81
|
+
# die Laufzeitschicht. Was ein Projekt in seine eigenen Dateien schreibt, geht das
|
|
82
|
+
# Framework nichts an; es darf eine Belegablage nennen, die den alten Namen traegt.
|
|
83
|
+
# Gemessen am 2026-09-22 im Uebungsrepositorium: zwei solche Nennungen, beide
|
|
84
|
+
# legitim nach D-300, und die Pruefung meldete sie als Fehler (D-299).
|
|
85
|
+
#
|
|
86
|
+
# ERKANNT WIRD DAS AM KENNZEICHEN DES QUELLREPOSITORIUMS (D-351). Bis 1.4.0 war es
|
|
87
|
+
# die Uebergabe; seit sie nicht mehr versioniert ist (D-350), traegt eine eigene
|
|
88
|
+
# Datei den Anker. Sie wandert NICHT in ein Zielprojekt; `install.py` legt sie nicht
|
|
89
|
+
# an, und das Heben kopiert nur den Kern. Ein Anker, der sich selbst belegt.
|
|
90
|
+
# ➡️ Eine Pruefung, die im Framework gruen und in jeder Installation rot ist, ist
|
|
91
|
+
# falsch gebaut - dieselbe Ueberlegung, mit der Pruefung 46 ihren Zaehlbereich auf
|
|
92
|
+
# den Kern beschraenkt: Was nicht in jeder Installation gleich ist, gehoert nicht in
|
|
93
|
+
# eine installationsunabhaengige Aussage.
|
|
94
|
+
#
|
|
95
|
+
# AUSGENOMMEN, UND ZWAR DEKLARIERT (dieselbe Bauform wie P73_OFFEN und LINK_EXCEPTIONS):
|
|
96
|
+
#
|
|
97
|
+
# (a) DIE CHRONIK. Protokolle, Aenderungsantraege, CHANGELOG und Decision Log
|
|
98
|
+
# beschreiben einen vergangenen Zustand (D-125, D-273). Ein Pfad, den es nicht
|
|
99
|
+
# mehr gibt, ist dort richtig - er hat damals existiert.
|
|
100
|
+
# (b) NAMEN DATIERTER BELEGABLAGEN AUSSERHALB DES REPOSITORIUMS. Die Erhebungen
|
|
101
|
+
# heissen `leitwerk-erhebungen-<datum>-<buendel>` und werden NICHT umbenannt:
|
|
102
|
+
# Eine Reihe von Belegablagen, deren Namenskonvention mitten in der Reihe
|
|
103
|
+
# wechselt, ist nicht mehr als Reihe auffindbar (D-300).
|
|
104
|
+
# (c) AUSSAGEN UEBER DEN ALTEN NAMEN. Der Changelog-Eintrag zu 0.7.0, die
|
|
105
|
+
# Entscheidungsaufzeichnung im Releaseplan und die Kommentare, die erklaeren,
|
|
106
|
+
# warum eine Stelle umgebaut wurde. Ein Sweep kehrt sie ins Sinnlose - das war
|
|
107
|
+
# der teuerste Befund des Umbenennungslaufs (D-301).
|
|
108
|
+
# (d) DER PRUEFAPPARAT DIESER PRUEFUNG SELBST. Dieser Validator traegt das Muster,
|
|
109
|
+
# und probe-pruefungen.py SCHREIBT den alten Namen in den Sondenbaum, um die
|
|
110
|
+
# Pruefung ueberhaupt messen zu koennen. Die Klasse ist strukturell
|
|
111
|
+
# unvermeidbar: Eine Pruefung, die einen Namen sucht, muss ihn nennen - und ihre
|
|
112
|
+
# Sonde muss ihn schreiben. Beide Traeger sind beim ersten Lauf dieser Pruefung
|
|
113
|
+
# aufgefallen, weil sie sich selbst gemeldet hat.
|
|
114
|
+
#
|
|
115
|
+
# IN BEIDE RICHTUNGEN GEPRUEFT. Ein nicht gelisteter Traeger mit Fundstelle faellt auf,
|
|
116
|
+
# ein gelisteter OHNE Fundstelle ebenso: Eine Ausnahme, die nichts mehr ausnimmt, sieht
|
|
117
|
+
# wie Sorgfalt aus und ist toter Code (0.57.1).
|
|
118
|
+
#
|
|
119
|
+
# PREIS, UND ER IST BENANNT: Die Ausnahme gilt je TRAEGER, nicht je Zeile. Eine neue,
|
|
120
|
+
# falsche Nennung in einem gelisteten Traeger faellt nicht auf. Die Gegenseite waere
|
|
121
|
+
# eine Zahl je Traeger - und eine Zahl, die gepflegt werden muss, wird nicht gepflegt
|
|
122
|
+
# (zweimal an derselben Tabelle dieses Projekts belegt).
|
|
123
|
+
#
|
|
124
|
+
# DER PREIS IST BEIM ERSTEN LAUF ANGEFALLEN, an der Chronik statt an der Ausnahmemenge:
|
|
125
|
+
# CHANGELOG.md fuehrt in Zeile 3 den Satz "Prozess: <pfad>/RELEASE_PROCESS.md", und
|
|
126
|
+
# tests/protocols/README.md nennt in Zeile 3 den Testkatalog. Beides sind KOPFZEILEN,
|
|
127
|
+
# die einen AKTUELLEN Pfad nennen - keine Chronik -, und die Chronikausnahme deckt sie
|
|
128
|
+
# mit. Beide sind von Hand nachgezogen worden.
|
|
129
|
+
# ➡️ Ein Chroniktraeger kann eine Zeile fuehren, die keine Chronik ist. Wer eine
|
|
130
|
+
# Ausnahme je Traeger zieht, liest den KOPF des Traegers, bevor er sie zieht.
|
|
131
|
+
P75_ALTNAME = re.compile(r"(?i)leitwerk")
|
|
132
|
+
|
|
133
|
+
P75_CHRONIK = (
|
|
134
|
+
KERN + "/CHANGELOG.md",
|
|
135
|
+
KERN + "/governance/DECISION_LOG.md",
|
|
136
|
+
KERN + "/governance/change-requests/",
|
|
137
|
+
KERN + "/tests/protocols/",
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
P75_AUSNAHMEN = {
|
|
141
|
+
# (b) Namen datierter Belegablagen ausserhalb des Repositoriums
|
|
142
|
+
KERN + "/tests/erhebungen/README.md",
|
|
143
|
+
KERN + "/tests/erhebungen/ablage.py",
|
|
144
|
+
KERN + "/tests/erhebungen/baeume-b4.py",
|
|
145
|
+
KERN + "/tests/erhebungen/umgebungen-bauen-b4.py",
|
|
146
|
+
KERN + "/tests/scripts/validate-framework.py",
|
|
147
|
+
KERN + "/tests/scripts/pruefungen/hooks.py",
|
|
148
|
+
# (c) Aussagen ueber den alten Namen
|
|
149
|
+
KERN + "/build/doc/32-abschluss.md",
|
|
150
|
+
KERN + "/clientmap.py",
|
|
151
|
+
# (d) Der Pruefapparat dieser Pruefung selbst - seit 1.19.1 in den Modulen, die
|
|
152
|
+
# ihr Muster und ihre Sonden tragen (K-174)
|
|
153
|
+
KERN + "/tests/scripts/pruefungen/dokumente.py",
|
|
154
|
+
KERN + "/tests/scripts/sonden/teil08_pruefungen_66_bis_80.py",
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _p75_chronik(rel: str) -> bool:
|
|
159
|
+
return any(rel == c or rel.startswith(c) for c in P75_CHRONIK)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _p75_verfolgt(root: str) -> list | None:
|
|
163
|
+
"""Alle verfolgten Pfade des Repositoriums - oder None, wenn nicht messbar.
|
|
164
|
+
|
|
165
|
+
Nicht _verfolgte_dateien(): die liest nur unter KERN, und der Zaehlbereich dieser
|
|
166
|
+
Pruefung ist ausdruecklich groesser (D-295).
|
|
167
|
+
"""
|
|
168
|
+
try:
|
|
169
|
+
lauf = subprocess.run(["git", "-C", root, "ls-files", "-z"],
|
|
170
|
+
capture_output=True, text=True, encoding="utf-8",
|
|
171
|
+
errors="replace", timeout=30)
|
|
172
|
+
except (OSError, subprocess.SubprocessError):
|
|
173
|
+
return None
|
|
174
|
+
if lauf.returncode != 0:
|
|
175
|
+
return None
|
|
176
|
+
return _git_pfade(lauf.stdout)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def check_altname_restbestand(root: str, man: dict) -> None:
|
|
180
|
+
"""Pruefung 75 (D-271): Kein Traeger nennt den alten Namen ausser den erklaerten."""
|
|
181
|
+
if not P75_ALTNAME.search("LeItWeRk"):
|
|
182
|
+
err("Prüfung 75: das eigene Muster findet den alten Namen nicht mehr – sie "
|
|
183
|
+
"bestünde leise und meldete jede Umbenennung als vollständig (D-23)")
|
|
184
|
+
return
|
|
185
|
+
dateien = _p75_verfolgt(root)
|
|
186
|
+
if dateien is None:
|
|
187
|
+
warn("Prüfung 75: kein Git-Bestand lesbar – der Restbestand des alten Namens "
|
|
188
|
+
"ist an diesem Ort nicht prüfbar. Das ist KEIN Messergebnis (D-23)")
|
|
189
|
+
return
|
|
190
|
+
bestand = set(dateien)
|
|
191
|
+
# Das Framework-Repositorium fuehrt das Kennzeichen; ein uebernehmendes Projekt
|
|
192
|
+
# nicht (D-351). Gelesen am VERSIONIERTEN Bestand, wie der Zaehlbereich selbst.
|
|
193
|
+
eigenes_repo = QUELLREPO_KENNZEICHEN in bestand
|
|
194
|
+
ausgeliefert = tuple(
|
|
195
|
+
d + "/" for d in (KERN, man.get("runtime_dir", "")) if d) + tuple(
|
|
196
|
+
f for f in (man.get("root_instruction_file", ""),) if f)
|
|
197
|
+
gefunden = set()
|
|
198
|
+
for rel in sorted(bestand):
|
|
199
|
+
if _p75_chronik(rel):
|
|
200
|
+
continue
|
|
201
|
+
if not eigenes_repo and not rel.startswith(ausgeliefert):
|
|
202
|
+
continue
|
|
203
|
+
if os.path.splitext(rel)[1] not in TEXT_EXT:
|
|
204
|
+
continue
|
|
205
|
+
pfad = os.path.join(root, *rel.split("/"))
|
|
206
|
+
if not os.path.isfile(pfad):
|
|
207
|
+
continue
|
|
208
|
+
treffer = P75_ALTNAME.findall(read(pfad))
|
|
209
|
+
if not treffer:
|
|
210
|
+
continue
|
|
211
|
+
gefunden.add(rel)
|
|
212
|
+
if rel in P75_AUSNAHMEN:
|
|
213
|
+
continue
|
|
214
|
+
err(f"{rel}: nennt den alten Namen noch {len(treffer)}mal. Das Framework heißt "
|
|
215
|
+
f"seit 0.88.0 Koolie, der Kern liegt unter {KERN} (D-271). Steht die Nennung "
|
|
216
|
+
f"dort mit Grund – eine Aufzeichnung, ein Belegablagenname –, gehört der "
|
|
217
|
+
f"Träger als MENGE in P75_AUSNAHMEN und wird nicht als Einzelfall "
|
|
218
|
+
f"durchgelassen")
|
|
219
|
+
for rel in sorted(P75_AUSNAHMEN - gefunden):
|
|
220
|
+
# EIN TRAEGER, DEN DIESE INSTALLATION NICHT FUEHRT, IST KEINE LEERE AUSNAHME.
|
|
221
|
+
# Die Menge beschreibt den Bestand des Framework-Repositoriums; ein
|
|
222
|
+
# uebernehmendes Projekt hat einen anderen - es fuehrt kein Kennzeichen, und
|
|
223
|
+
# sein Kern ist erst nach dem ersten `git add` verfolgt. Ohne diese
|
|
224
|
+
# Unterscheidung waere die Pruefung im Framework gruen und in JEDER
|
|
225
|
+
# Installation rot; gemessen am 2026-09-22 im Uebungsrepositorium, mit neun
|
|
226
|
+
# Meldungen (D-299). Pruefung 46 loest denselben Anspruch mit demselben
|
|
227
|
+
# Gedanken: Was nicht in jeder Installation gleich ist, gehoert nicht in eine
|
|
228
|
+
# installationsunabhaengige Aussage.
|
|
229
|
+
if rel not in bestand:
|
|
230
|
+
continue
|
|
231
|
+
err(f"P75_AUSNAHMEN führt '{rel}' als erklärte Fundstelle des alten Namens – "
|
|
232
|
+
f"dort steht er nicht mehr. Die Ausnahme nimmt nichts mehr aus und "
|
|
233
|
+
f"gehört entfernt (0.57.1)")
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
# ---------------------------------------------------------------------------
|
|
237
|
+
# Pruefung 77: Das Hauptdokument nennt den Stand, auf dem es gebaut ist
|
|
238
|
+
# ---------------------------------------------------------------------------
|
|
239
|
+
#
|
|
240
|
+
# Sie war die Schwester der mit 1.4.1 entfallenen Pruefung 67 (D-350). Dort hielt die
|
|
241
|
+
# Titelzeile der Uebergabe gegen VERSION, hier die Kopfzeile des Hauptdokuments - und
|
|
242
|
+
# der Unterschied war, dass die Uebergabe jede Sitzung gelesen wurde und das
|
|
243
|
+
# Hauptdokument nur zur Auslieferung.
|
|
244
|
+
# Genau deshalb ist es zweiundvierzig Releases zurueckgefallen, ohne dass es jemandem
|
|
245
|
+
# aufgefallen waere.
|
|
246
|
+
#
|
|
247
|
+
# WARUM DIE QUELLE UND NICHT DAS ERZEUGNIS. build/out/hauptdokument.md steht in der
|
|
248
|
+
# .gitignore und ist in einer frischen Auscheckung gar nicht da; eine Pruefung dagegen
|
|
249
|
+
# waere in jeder Installation rot. Der Gegenstand ist die KAPITELQUELLE, und die ist
|
|
250
|
+
# versioniert - derselbe Gedanke wie bei Pruefung 46 und 75.
|
|
251
|
+
DOKUMENT_KOPF = KERN + "/build/doc/00-kopf.md"
|
|
252
|
+
DOKUMENT_VERSION_RE = re.compile(
|
|
253
|
+
r"^\|\s*Dokumentversion\s*\|\s*(\d+\.\d+\.\d+)\s*"
|
|
254
|
+
r"\(entspricht Framework-Release\s*(\d+\.\d+\.\d+)\)\s*\|", re.M)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def check_dokumentstand(root: str) -> None:
|
|
258
|
+
"""Pruefung 77 (D-312): Das Hauptdokument steht auf dem Stand des Kerns."""
|
|
259
|
+
pfad = os.path.join(root, *DOKUMENT_KOPF.split("/"))
|
|
260
|
+
if not os.path.isfile(pfad) and nicht_geliefert(root, DOKUMENT_KOPF):
|
|
261
|
+
hinweis(f"Prüfung 77 ohne Gegenstand: {DOKUMENT_KOPF} gehört zur Nachweisschicht "
|
|
262
|
+
f"und ist nicht geliefert (D-367)")
|
|
263
|
+
return
|
|
264
|
+
if not os.path.isfile(pfad):
|
|
265
|
+
err(f"{DOKUMENT_KOPF}: fehlt. Prüfung 77 hält dort die Dokumentversion gegen "
|
|
266
|
+
f"{KERN}/VERSION; ohne den Träger hat sie ihren Gegenstand verloren (D-312)")
|
|
267
|
+
return
|
|
268
|
+
vpfad = os.path.join(root, KERN, "VERSION")
|
|
269
|
+
if not os.path.isfile(vpfad):
|
|
270
|
+
return # Pruefung 1 meldet die fehlende Pflichtdatei bereits
|
|
271
|
+
stand = read(vpfad).strip()
|
|
272
|
+
m = DOKUMENT_VERSION_RE.search(read(pfad))
|
|
273
|
+
if not m:
|
|
274
|
+
err(f"{DOKUMENT_KOPF}: keine Zeile der Form "
|
|
275
|
+
f"`| Dokumentversion | X.Y.Z (entspricht Framework-Release X.Y.Z) |`. "
|
|
276
|
+
f"Prüfung 77 hält sie gegen {KERN}/VERSION und bestünde ohne sie leise – "
|
|
277
|
+
f"genau der Zustand, in dem das Dokument 42 Releases zurückgefallen ist "
|
|
278
|
+
f"(D-312, D-23)")
|
|
279
|
+
return
|
|
280
|
+
dokument, genannt = m.group(1), m.group(2)
|
|
281
|
+
if dokument != genannt:
|
|
282
|
+
err(f"{DOKUMENT_KOPF}: die Kopfzeile nennt die Dokumentversion {dokument} und "
|
|
283
|
+
f"das Framework-Release {genannt}. Die Zeile sagt aus, dass beide "
|
|
284
|
+
f"übereinstimmen; nennt sie zwei Werte, lässt sie offen, auf welchem Stand "
|
|
285
|
+
f"das Dokument gebaut ist (D-312)")
|
|
286
|
+
return
|
|
287
|
+
if dokument != stand:
|
|
288
|
+
err(f"{DOKUMENT_KOPF}: die Kopfzeile nennt den Stand {dokument}, "
|
|
289
|
+
f"{KERN}/VERSION führt {stand}. Das Hauptdokument wird aus diesem "
|
|
290
|
+
f"Repositorium assembliert und hat keinen eigenen Stand; eine abweichende "
|
|
291
|
+
f"Zahl behauptet einen Bau, den es nicht gegeben hat (D-312)")
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
# ---------------------------------------------------------------------------
|
|
295
|
+
# Pruefung 78: Die zaehlbaren Aussagen des Hauptdokuments (CR-2026-125, D-315)
|
|
296
|
+
# ---------------------------------------------------------------------------
|
|
297
|
+
#
|
|
298
|
+
# ANLASS, UND ER IST DAS RELEASE DAVOR. 0.89.0 hat das Hauptdokument nach ZWEIUNDVIERZIG
|
|
299
|
+
# Releases auf den geltenden Stand gesetzt und dabei vierzehn stehengebliebene Zahlen
|
|
300
|
+
# berichtigt. Sein eigenes Protokoll schreibt den Grund auf:
|
|
301
|
+
# "Das ist die Bauform von Pruefung 40 an einem groesseren Gegenstand - und der
|
|
302
|
+
# Grund, warum die Behebung eine PRUEFUNG braucht und nicht nur eine Textaenderung."
|
|
303
|
+
# Gebaut wurde dann Pruefung 77, und die misst die VERSION, nicht den INHALT. Gemessen am
|
|
304
|
+
# 2026-09-23, EIN Release spaeter: Der Satz in 26-qs-test.md nannte "76 Pruefungen ueber
|
|
305
|
+
# 502 versionierte Dateien, davon 450 Markdown-Dateien". Richtig waren 77, 504 und 452 -
|
|
306
|
+
# und die beiden Dateien, die fehlten, waren der Antrag und das Protokoll DESSELBEN
|
|
307
|
+
# Releases. DREI ZAHLEN IN EINEM SATZ, UEBERHOLT IM RELEASE, DAS DAS DOKUMENT AUF DEN
|
|
308
|
+
# GELTENDEN STAND GESETZT HAT.
|
|
309
|
+
#
|
|
310
|
+
# DIE BAUFORM IST DIE VON PRUEFUNG 40: den Satz AUSRECHNEN und woertlich verlangen. Ein
|
|
311
|
+
# Vergleich einzelner Zahlen liesse offen, in welchem Satz sie stehen; ein woertlicher
|
|
312
|
+
# Sollsatz sagt zugleich, wie er zu schreiben ist.
|
|
313
|
+
#
|
|
314
|
+
# ZUSCHNITT, UND ER IST DER GANZE PUNKT (D-318): Diese Pruefung gilt der GEGENWARTSFORM.
|
|
315
|
+
# "Der Validator fuehrt 79 Pruefungen" ist eine Aussage ueber jetzt und veraltet.
|
|
316
|
+
# "Gezaehlt am 2026-09-22: 312 Decision Records" ist eine DATIERTE Aussage und veraltet
|
|
317
|
+
# nie - sie muss nur fuer ihr Datum stimmen. Die datierten Zahlen stehen in 29-grenzen.md
|
|
318
|
+
# und 32-abschluss.md, beide ausgewiesene Zeitdokumente (D-273, D-311), und werden hier
|
|
319
|
+
# ausdruecklich NICHT geprueft. Eine Pruefung, die ein Zeitdokument fortzuschreiben
|
|
320
|
+
# verlangt, hat seinen Zweck nicht verstanden.
|
|
321
|
+
#
|
|
322
|
+
# GRENZE, benannt: Sie misst DREI Zahlen in EINEM Satz. Jede andere Zahl des Dokuments
|
|
323
|
+
# laeuft weiter durch - das ist der Rest von K-104, und er ist nicht kleiner geworden,
|
|
324
|
+
# nur gezaehlt.
|
|
325
|
+
#
|
|
326
|
+
# ZWEITER GEGENSTAND VON 1.0.0 BIS 1.4.0 (D-325): DIE ABNAHMEZEILE DER UEBERGABE.
|
|
327
|
+
# ENTFALLEN mit 1.4.1 (D-350) - die Uebergabe ist nicht mehr versioniert, und eine
|
|
328
|
+
# Pruefung gegen einen Traeger, den eine frische Auscheckung nicht fuehrt, liefe nur
|
|
329
|
+
# an einem Arbeitsplatz. Die Lehre bleibt stehen, weil sie ueber die Uebergabe
|
|
330
|
+
# hinausreicht: WER EINE ZAHL PRUEFT, SUCHT IHRE ZWEITE FUNDSTELLE (D-295).
|
|
331
|
+
#
|
|
332
|
+
# ENTHALTUNG: Ein uebernehmendes Projekt fuehrt das Kennzeichen des
|
|
333
|
+
# Quellrepositoriums nicht (D-351). Dort enthaelt sich die ganze Pruefung (D-326).
|
|
334
|
+
P78_TRAEGER = KERN + "/build/doc/26-qs-test.md"
|
|
335
|
+
P78_ANKER = "Der Validator führt **"
|
|
336
|
+
P78_SATZ = ("Der Validator führt **{0} Prüfungen** über {1} versionierte Dateien des "
|
|
337
|
+
"Kerns, davon {2} Markdown-Dateien")
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def check_dokumentzahlen(root: str) -> None:
|
|
341
|
+
"""Pruefung 78 (D-315): Die Gegenwartszahlen des Hauptdokuments gegen den Bestand."""
|
|
342
|
+
# 🔴 ENTHALTUNG IM UEBERNEHMENDEN PROJEKT (D-326, gemessen am 2026-09-23).
|
|
343
|
+
# Der Satz beschreibt den Bestand des FRAMEWORK-Repositoriums und wird byte-gleich
|
|
344
|
+
# ausgeliefert (D-25). Ein uebernehmendes Projekt fuehrt weniger Kerndateien - beim
|
|
345
|
+
# ersten Lauf dieser Pruefung gegen eines waren es 500 gegen 515 -, und es pflegt den
|
|
346
|
+
# Traeger nicht. Ohne diese Unterscheidung waere sie im Framework gruen und in JEDER
|
|
347
|
+
# Installation rot; das ist der Konstruktionsfehler aus D-299, und die Lehre stand im
|
|
348
|
+
# SELBEN Release, das diese Pruefung gebaut hat.
|
|
349
|
+
if not ist_quellrepositorium(root):
|
|
350
|
+
return
|
|
351
|
+
pfad = os.path.join(root, *P78_TRAEGER.split("/"))
|
|
352
|
+
if not os.path.isfile(pfad):
|
|
353
|
+
err(f"{P78_TRAEGER}: fehlt. Prüfung 78 hält dort die zählbaren Aussagen des "
|
|
354
|
+
f"Hauptdokuments gegen den Bestand (D-315)")
|
|
355
|
+
return
|
|
356
|
+
text = read(pfad)
|
|
357
|
+
# --- Gegenstand 1: der Anker ---------------------------------------------------
|
|
358
|
+
if text.count(P78_ANKER) != 1:
|
|
359
|
+
err(f"{P78_TRAEGER}: der Satz über den Prüfapparat steht nicht genau einmal "
|
|
360
|
+
f"(gesucht: '{P78_ANKER}', gefunden: {text.count(P78_ANKER)}x). Prüfung 78 "
|
|
361
|
+
f"hat ihren Gegenstand verloren und bestünde sonst leise (D-23)")
|
|
362
|
+
return
|
|
363
|
+
# --- Gegenstand 2: die Zahl der Pruefungen --------------------------------------
|
|
364
|
+
vpfad = os.path.join(root, KERN, "tests", "scripts", "validate-framework.py")
|
|
365
|
+
if not os.path.isfile(vpfad):
|
|
366
|
+
return # Pruefung 40 meldet den verlorenen Traeger bereits
|
|
367
|
+
doc = read(vpfad)
|
|
368
|
+
doc = doc.split('"""')[1] if doc.count('"""') >= 2 else ""
|
|
369
|
+
if REGISTER_ANKER not in doc or REGISTER_ENDE not in doc:
|
|
370
|
+
return # Pruefung 40 meldet das verlorene Register bereits
|
|
371
|
+
liste = doc.split(REGISTER_ANKER, 1)[1].split(REGISTER_ENDE, 1)[0]
|
|
372
|
+
gefuehrt = sorted({int(n) for n in re.findall(r"^\s{0,2}(\d+)[a-z]?\. ", liste, re.M)})
|
|
373
|
+
if not gefuehrt:
|
|
374
|
+
return # ebenfalls Pruefung 40
|
|
375
|
+
# --- Gegenstand 3: der Bestand ---------------------------------------------------
|
|
376
|
+
dateien = _verfolgte_dateien(root)
|
|
377
|
+
if dateien is None:
|
|
378
|
+
warn("Prüfung 78: kein Git-Bestand lesbar – die Zahl der versionierten Dateien "
|
|
379
|
+
"ist an diesem Ort nicht prüfbar. Das ist KEIN Messergebnis (D-23)")
|
|
380
|
+
return
|
|
381
|
+
soll = P78_SATZ.format(gefuehrt[-1], len(dateien),
|
|
382
|
+
sum(1 for d in dateien if d.endswith(".md")))
|
|
383
|
+
if soll not in text:
|
|
384
|
+
err(f"{P78_TRAEGER}: der Satz über den Prüfapparat nennt nicht die gezählten "
|
|
385
|
+
f"Werte. Erwartet wörtlich: '{soll}'. Gezählt wurden {gefuehrt[-1]} "
|
|
386
|
+
f"Prüfungen im Register, {len(dateien)} versionierte Dateien unter {KERN}/ "
|
|
387
|
+
f"und {sum(1 for d in dateien if d.endswith('.md'))} davon als Markdown. "
|
|
388
|
+
f"Bis 0.89.0 standen hier 76, 502 und 450 – alle drei waren in DEM Release "
|
|
389
|
+
f"überholt, das das Dokument auf den geltenden Stand gesetzt hat (D-315)")
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
# ---------------------------------------------------------------------------
|
|
393
|
+
# Pruefung 79: Die Lizenz liegt an zwei Stellen und ist dieselbe (CR-2026-126, D-317)
|
|
394
|
+
# ---------------------------------------------------------------------------
|
|
395
|
+
#
|
|
396
|
+
# ZWEI STELLEN, UND BEIDE WERDEN GEBRAUCHT: Die Wurzel, weil die Hostingdienste die
|
|
397
|
+
# Lizenz dort suchen und ein Repositorium ohne erkannte Lizenz als "alle Rechte
|
|
398
|
+
# vorbehalten" gilt. Der Kern, weil ein uebernehmendes Projekt ihn ALS GANZES kopiert
|
|
399
|
+
# (docs/ADOPTION_GUIDE.md Schritt 2) - eine Lizenzdatei, die nur in der Wurzel liegt,
|
|
400
|
+
# wandert dabei nicht mit, und ein Werk ohne seine Lizenz weiterzugeben ist nach
|
|
401
|
+
# §4 GPL-3.0 unzulaessig.
|
|
402
|
+
#
|
|
403
|
+
# WARUM DAS EINE PRUEFUNG BRAUCHT: Zwei Stellen mit demselben Inhalt laufen auseinander,
|
|
404
|
+
# sobald eine von beiden angefasst wird. Das ist in diesem Repositorium der haeufigste
|
|
405
|
+
# Befundtyp, und die Antwort darauf ist dieselbe wie bei Pruefung 76: nicht "bitte beide
|
|
406
|
+
# pflegen", sondern ein Vergleich, der meldet.
|
|
407
|
+
#
|
|
408
|
+
# GRENZE, benannt: Sie vergleicht die beiden Dateien MITEINANDER und prueft, dass es die
|
|
409
|
+
# GPL-3.0 ist. Sie prueft nicht, ob der Text der amtlichen Fassung der Free Software
|
|
410
|
+
# Foundation entspricht - dafuer waere ein Netzzugriff noetig, und eine Pruefung, die
|
|
411
|
+
# das Netz braucht, ist in einer Installation nicht fahrbar.
|
|
412
|
+
#
|
|
413
|
+
# 🔴 BERICHTIGT MIT 1.0.0 (D-326, CR-2026-128 B14): DIE WURZELFASSUNG GILT NUR IM
|
|
414
|
+
# FRAMEWORK-REPOSITORIUM. Gemessen am 2026-09-23 beim ersten Lauf dieser Pruefung gegen
|
|
415
|
+
# ein uebernehmendes Projekt: Sie meldete "LICENSE: fehlt" - und verlangte damit von
|
|
416
|
+
# JEDEM uebernehmenden Projekt eine GPL-3.0 in SEINER Wurzel.
|
|
417
|
+
# 🔴 DAS WAERE DAS GEGENTEIL DESSEN, WAS DIESELBE ENTSCHEIDUNG WOLLTE: Die
|
|
418
|
+
# Zusatzerlaubnis nach §7 (D-317, Abschnitt 2 des Lizenzhinweises) nimmt die Ausgaben
|
|
419
|
+
# und ausgefuellten Vorlagen ausdruecklich AUS der GPL heraus, damit ein Projekt nicht
|
|
420
|
+
# zur Offenlegung gezwungen wird. Eine Pruefung, die dem Projekt die GPL in die Wurzel
|
|
421
|
+
# schreibt, hebt genau das wieder auf.
|
|
422
|
+
# ➡️ EINE PRUEFUNG, DIE IM FRAMEWORK GRUEN UND IN JEDER INSTALLATION ROT IST, IST FALSCH
|
|
423
|
+
# GEBAUT (D-299) - und die Lehre stand im SELBEN Release, das diese Pruefung gebaut
|
|
424
|
+
# hat: "Jede neue Pruefung laeuft einmal gegen ein uebernehmendes Projekt, bevor sie
|
|
425
|
+
# als fertig gilt." Sie ist notiert und nicht angewandt worden.
|
|
426
|
+
#
|
|
427
|
+
# ZUSCHNITT seit 1.0.0: Im uebernehmenden Projekt gilt allein die KERNFASSUNG - sie ist
|
|
428
|
+
# die, die nach §4 GPL-3.0 mitwandern muss. Die Wurzel gehoert dem Projekt.
|
|
429
|
+
P79_WURZEL = "LICENSE"
|
|
430
|
+
P79_KERN = KERN + "/LICENSE"
|
|
431
|
+
P79_MARKE = "GNU GENERAL PUBLIC LICENSE"
|
|
432
|
+
P79_VERSION = "Version 3, 29 June 2007"
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def check_lizenz(root: str) -> None:
|
|
436
|
+
"""Pruefung 79 (D-317): Die Lizenz liegt an beiden Stellen und ist dieselbe."""
|
|
437
|
+
# Das Framework-Repositorium fuehrt das Kennzeichen; ein uebernehmendes Projekt
|
|
438
|
+
# nicht (D-351). Dort gilt allein die Kernfassung - die Wurzel gehoert dem
|
|
439
|
+
# Projekt (D-326).
|
|
440
|
+
eigenes_repo = ist_quellrepositorium(root)
|
|
441
|
+
stellen = (P79_WURZEL, P79_KERN) if eigenes_repo else (P79_KERN,)
|
|
442
|
+
inhalte = {}
|
|
443
|
+
for rel in stellen:
|
|
444
|
+
pfad = os.path.join(root, *rel.split("/"))
|
|
445
|
+
if not os.path.isfile(pfad):
|
|
446
|
+
err(f"{rel}: fehlt. Die Lizenz MUSS an beiden Stellen liegen – in der Wurzel "
|
|
447
|
+
f"für die Erkennung durch die Hostingdienste, im Kern, weil ein "
|
|
448
|
+
f"übernehmendes Projekt ihn als Ganzes kopiert und die Lizenz sonst nicht "
|
|
449
|
+
f"mitwandert (§4 GPL-3.0, D-317)")
|
|
450
|
+
return
|
|
451
|
+
with open(pfad, "rb") as fh:
|
|
452
|
+
inhalte[rel] = fh.read()
|
|
453
|
+
if not eigenes_repo:
|
|
454
|
+
# Kein Vergleich moeglich und keiner noetig: Was mitwandern muss, ist da.
|
|
455
|
+
text = inhalte[P79_KERN].decode("utf-8", "replace")
|
|
456
|
+
if P79_MARKE not in text or P79_VERSION not in text:
|
|
457
|
+
err(f"{P79_KERN}: trägt nicht die GNU General Public License Version 3 "
|
|
458
|
+
f"(gesucht: '{P79_MARKE}' und '{P79_VERSION}'). Der Kern wandert mit "
|
|
459
|
+
f"seiner Lizenz oder gar nicht (§4 GPL-3.0, D-317, D-326)")
|
|
460
|
+
return
|
|
461
|
+
if inhalte[P79_WURZEL] != inhalte[P79_KERN]:
|
|
462
|
+
err(f"{P79_KERN}: trägt nicht denselben Inhalt wie {P79_WURZEL} "
|
|
463
|
+
f"({len(inhalte[P79_WURZEL])} gegen {len(inhalte[P79_KERN])} Bytes). Zwei "
|
|
464
|
+
f"Lizenzdateien mit verschiedenem Inhalt lassen offen, welche gilt – und für "
|
|
465
|
+
f"ein übernehmendes Projekt gilt die aus dem Kern (D-317)")
|
|
466
|
+
return
|
|
467
|
+
text = inhalte[P79_WURZEL].decode("utf-8", "replace")
|
|
468
|
+
if P79_MARKE not in text or P79_VERSION not in text:
|
|
469
|
+
err(f"{P79_WURZEL}: trägt nicht die GNU General Public License Version 3 "
|
|
470
|
+
f"(gesucht: '{P79_MARKE}' und '{P79_VERSION}'). Prüfung 79 hätte sonst nur "
|
|
471
|
+
f"belegt, dass zwei Dateien gleich sind – auch zwei leere sind das (D-23)")
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
# ---------------------------------------------------------------------------
|
|
475
|
+
# Pruefung 80: Jedes Abnahmeprotokoll traegt seine Gegenzeichnung (CR-2026-127, D-319)
|
|
476
|
+
# ---------------------------------------------------------------------------
|
|
477
|
+
#
|
|
478
|
+
# ANLASS. AP11 verlangte die Gegenzeichnung der Protokolle. 0.89.0 hat sie nicht
|
|
479
|
+
# gefahren und den Grund als ABGRENZUNG aufgeschrieben: Eine Gegenzeichnung ist die
|
|
480
|
+
# Handlung einer ZWEITEN ROLLE, und ein Werkzeug, das <TBD: Rolle> ersetzt, faelscht
|
|
481
|
+
# sie. Das traegt - und es hatte eine Folge, die niemand benannt hatte: An diesem
|
|
482
|
+
# Framework arbeitet EINE Person. Die Pflicht war in ihrer damaligen Form nicht
|
|
483
|
+
# erfuellbar, und zwar konstruktiv. Das ist die Bauform "die Regel mit leerer
|
|
484
|
+
# Schnittmenge" (D-189, K-72) an einer GOVERNANCE-Regel statt an einer Testzelle.
|
|
485
|
+
#
|
|
486
|
+
# DER ZUSCHNITT IST DIE HALBE ENTSCHEIDUNG (D-319). Nicht jedes Protokoll ist eine
|
|
487
|
+
# Abnahme: Von 125 sind die meisten Arbeits- und Messprotokolle, die ihren Beleg in
|
|
488
|
+
# sich tragen. Eine Gegenzeichnung sagt etwas anderes - eine zweite Person hat geprueft
|
|
489
|
+
# und steht dafuer ein. Gemessen am 2026-09-23 ueber BEIDE Zaehlregeln: Der Gesamtbestand
|
|
490
|
+
# ergibt 17/47/61 oder 13/45/64, je nach Regel; die ZEHN Abnahmeprotokolle ergeben
|
|
491
|
+
# 3/2/5 unter BEIDEN. Ein Gegenstand, der unter zwei Regeln derselbe ist, ist der
|
|
492
|
+
# richtige Gegenstand.
|
|
493
|
+
#
|
|
494
|
+
# WAS SIE PRUEFT UND WAS NICHT. Sie prueft, dass der Abschnitt DA ist und kein offenes
|
|
495
|
+
# <TBD> mehr traegt. Sie prueft NICHT, ob jemand wirklich gelesen hat - das kann kein
|
|
496
|
+
# Skript, und deshalb steht neben der Zeile der Commit: Die Zeile sagt, WAS
|
|
497
|
+
# gegengezeichnet wurde, der Commit sagt, WER. Eine Unterschrift, die ein Werkzeug
|
|
498
|
+
# erzeugen kann, belegt nichts; diese Pruefung erzeugt keine, sie verlangt eine.
|
|
499
|
+
#
|
|
500
|
+
# GRENZE, benannt: Sie erkennt ein Abnahmeprotokoll am DATEINAMEN. Ein Protokoll, das
|
|
501
|
+
# anders heisst, laeuft durch - dieselbe Ehrlichkeit wie bei Pruefung 48, die Pfade
|
|
502
|
+
# findet und keine Prosa.
|
|
503
|
+
P80_ABLAGE = KERN + "/tests/protocols"
|
|
504
|
+
P80_NAME = re.compile(r"^\d{4}-\d{2}-\d{2}-FW-[A-Z]{2}-\d{2}[\w.-]*\.md$")
|
|
505
|
+
P80_ABSCHNITT = re.compile(r"^#{1,6}\s.*Gegenzeichnung", re.M | re.I)
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
def check_gegenzeichnung(root: str) -> None:
|
|
509
|
+
"""Pruefung 80 (D-319): Abnahmeprotokolle tragen ihre Gegenzeichnung."""
|
|
510
|
+
ablage = os.path.join(root, *P80_ABLAGE.split("/"))
|
|
511
|
+
if not os.path.isdir(ablage) and nicht_geliefert(root, P80_ABLAGE):
|
|
512
|
+
hinweis(f"Prüfung 80 ohne Gegenstand: {P80_ABLAGE}/ gehört zur Nachweisschicht "
|
|
513
|
+
f"und ist nicht geliefert (D-367)")
|
|
514
|
+
return
|
|
515
|
+
if not os.path.isdir(ablage):
|
|
516
|
+
err(f"{P80_ABLAGE}/: fehlt. Prüfung 80 hält dort die Gegenzeichnung der "
|
|
517
|
+
f"Abnahmeprotokolle; ohne die Ablage hat sie ihren Gegenstand verloren "
|
|
518
|
+
f"(D-319)")
|
|
519
|
+
return
|
|
520
|
+
# --- Gegenstand 1: der Anker ---------------------------------------------------
|
|
521
|
+
kandidaten = sorted(n for n in os.listdir(ablage) if P80_NAME.match(n))
|
|
522
|
+
if not kandidaten:
|
|
523
|
+
err(f"{P80_ABLAGE}/: kein einziges Abnahmeprotokoll des Testkatalogs gefunden "
|
|
524
|
+
f"(Muster `JJJJ-MM-TT-FW-<Klasse>-<NN>.md`). Prüfung 80 hätte nichts zu "
|
|
525
|
+
f"prüfen und bestünde leise – genau der Zustand, aus dem die Pflicht "
|
|
526
|
+
f"zweiundzwanzig Releases lang unbemerkt offen war (D-23, D-319)")
|
|
527
|
+
return
|
|
528
|
+
# --- Gegenstand 2: Abschnitt vorhanden und ohne offenes <TBD> -------------------
|
|
529
|
+
for name in kandidaten:
|
|
530
|
+
text = read(os.path.join(ablage, name))
|
|
531
|
+
treffer = P80_ABSCHNITT.search(text)
|
|
532
|
+
if not treffer:
|
|
533
|
+
err(f"{P80_ABLAGE}/{name}: kein Abschnitt `Gegenzeichnung`. Ein "
|
|
534
|
+
f"Abnahmeprotokoll des Testkatalogs trägt ihn (D-319, `FW-CL-11`). "
|
|
535
|
+
f"Arbeits- und Meßprotokolle bekommen ihn nicht – die Abgrenzung steht "
|
|
536
|
+
f"in `{P80_ABLAGE}/README.md`")
|
|
537
|
+
continue
|
|
538
|
+
abschnitt = text[treffer.start():]
|
|
539
|
+
naechste = re.search(r"^#{1,6}\s", abschnitt[treffer.end() - treffer.start():],
|
|
540
|
+
re.M)
|
|
541
|
+
if naechste:
|
|
542
|
+
abschnitt = abschnitt[:treffer.end() - treffer.start() + naechste.start()]
|
|
543
|
+
if TBD_RE.search(abschnitt):
|
|
544
|
+
err(f"{P80_ABLAGE}/{name}: der Abschnitt `Gegenzeichnung` trägt noch ein "
|
|
545
|
+
f"offenes `<TBD>`. Eine Gegenzeichnung ist die Handlung einer Rolle und "
|
|
546
|
+
f"kein Feld, das ein Werkzeug füllt – ist keine zweite Rolle vorhanden, "
|
|
547
|
+
f"wird selbst gegengezeichnet und der Abschnitt weist das ausdrücklich "
|
|
548
|
+
f"aus (D-319, `CR-2026-127` E1)")
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
# Pruefung 81: eine Zeilenendeform je Repositorium (CR-2026-128, D-320, K-81)
|
|
552
|
+
# ---------------------------------------------------------------------------
|
|
553
|
+
#
|
|
554
|
+
# ANLASS, und er ist ein eigener Fehler. Eine Sitzung hat 28 LF-Zeilen in einen Bestand
|
|
555
|
+
# eingeschleppt, der durchgehend CRLF traegt. Gefunden hat es KEINE der 80 Pruefungen,
|
|
556
|
+
# sondern ein Suchtext, der danach nicht mehr traf. Pruefung 66 prueft die
|
|
557
|
+
# GEGENRICHTUNG - einen Wagenruecklauf ohne Zeilenvorschub - und greift hier nicht.
|
|
558
|
+
#
|
|
559
|
+
# 🔴 UND DER BEFUND, DER IHN AUSLOESTE, WAR AM FALSCHEN GEGENSTAND GEMESSEN. Die
|
|
560
|
+
# Uebergabe schrieb "kein VERSIONIERTER Texttraeger traegt reine LF". Gemessen am
|
|
561
|
+
# 2026-09-23 ueber alle 517 verfolgten Eintraege: im ARBEITSBAUM 515 auf CRLF, im BLOB
|
|
562
|
+
# 515 auf reinem LF. Versioniert ist der Blob. Die Aussage ist an einem Gegenstand
|
|
563
|
+
# richtig und am anderen in ihr Gegenteil verkehrt.
|
|
564
|
+
# ➡️ WER EINE ZEILENENDEFORM MISST, SAGT DAZU, WELCHEN GEGENSTAND ER GEMESSEN HAT.
|
|
565
|
+
#
|
|
566
|
+
# ZUSCHNITT: DEN ARBEITSBAUM, NICHT DEN BLOB. Der Blob ist seit D-320 durch die
|
|
567
|
+
# .gitattributes gesetzt (`* text=auto`) - dort braucht es keine Pruefung, sondern eine
|
|
568
|
+
# Datei. Was die .gitattributes NICHT sieht, ist der Arbeitsbaum zwischen zwei
|
|
569
|
+
# Auscheckungen, und genau dort lag der Fall.
|
|
570
|
+
#
|
|
571
|
+
# SIE SCHREIBT KEINE FORM VOR. Sie verlangt, dass es EINE ist. Ein Linux-Arbeitsbaum
|
|
572
|
+
# traegt LF, ein Windows-Arbeitsbaum CRLF, und beide sind richtig; ein Bestand, der
|
|
573
|
+
# beides mischt, ist es nirgends. ➡️ EINHEITLICHKEIT IST IN JEDER INSTALLATION RICHTIG,
|
|
574
|
+
# EINE BESTIMMTE FORM NUR AN EINEM ARBEITSPLATZ. Damit ist der Konstruktionsfehler
|
|
575
|
+
# ausgeschlossen, den D-299 benannt hat: im Framework gruen und in jeder Installation rot.
|
|
576
|
+
#
|
|
577
|
+
# ZAEHLBEREICH wie bei Pruefung 75: die verfolgten Dateien. Im Framework-Repositorium
|
|
578
|
+
# (erkennbar am Kennzeichen, D-351) alle; in einem uebernehmenden Projekt nur die
|
|
579
|
+
# ausgelieferten - was ein Projekt in SEINEN Dateien fuer eine Form fuehrt, geht das
|
|
580
|
+
# Framework nichts an.
|
|
581
|
+
#
|
|
582
|
+
# GRENZE, benannt: Sie liest BYTES und misst den Arbeitsbaum. Welche Form im
|
|
583
|
+
# Repositorium ankommt, entscheidet die .gitattributes und nicht diese Pruefung. Ohne
|
|
584
|
+
# Git-Bestand meldet sie eine Warnung und KEIN Messergebnis (D-23).
|
|
585
|
+
P81_GEMISCHT = "gemischt"
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
def _p81_form(pfad: str) -> str | None:
|
|
589
|
+
"""Die Zeilenendeform eines Traegers, an seinen Bytes gemessen."""
|
|
590
|
+
try:
|
|
591
|
+
with open(pfad, "rb") as fh:
|
|
592
|
+
roh = fh.read()
|
|
593
|
+
except OSError:
|
|
594
|
+
return None
|
|
595
|
+
if b"\x00" in roh[:8000]:
|
|
596
|
+
return None
|
|
597
|
+
lf = roh.count(b"\n")
|
|
598
|
+
if not lf:
|
|
599
|
+
return None # ein Traeger ohne Zeilenumbruch traegt keine Form
|
|
600
|
+
crlf = roh.count(b"\r\n")
|
|
601
|
+
if crlf == lf:
|
|
602
|
+
return "CRLF"
|
|
603
|
+
if crlf == 0:
|
|
604
|
+
return "LF"
|
|
605
|
+
return P81_GEMISCHT
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
def check_zeilenendeform(root: str) -> None:
|
|
609
|
+
"""Pruefung 81 (D-320): Alle versionierten Texttraeger tragen dieselbe Form."""
|
|
610
|
+
dateien = _p75_verfolgt(root)
|
|
611
|
+
if dateien is None:
|
|
612
|
+
warn("Prüfung 81: kein Git-Bestand lesbar – die Zeilenendeform ist an diesem "
|
|
613
|
+
"Ort nicht prüfbar. Das ist KEIN Messergebnis (D-23)")
|
|
614
|
+
return
|
|
615
|
+
bestand = set(dateien)
|
|
616
|
+
eigenes_repo = QUELLREPO_KENNZEICHEN in bestand
|
|
617
|
+
ausgeliefert = (KERN + "/",)
|
|
618
|
+
formen: dict[str, list[str]] = {}
|
|
619
|
+
for rel in sorted(bestand):
|
|
620
|
+
if not eigenes_repo and not rel.startswith(ausgeliefert):
|
|
621
|
+
continue
|
|
622
|
+
if os.path.splitext(rel)[1] not in TEXT_EXT and os.path.basename(rel) not in (
|
|
623
|
+
"VERSION", ".gitignore", ".gitattributes"):
|
|
624
|
+
continue
|
|
625
|
+
pfad = os.path.join(root, *rel.split("/"))
|
|
626
|
+
if not os.path.isfile(pfad):
|
|
627
|
+
continue
|
|
628
|
+
form = _p81_form(pfad)
|
|
629
|
+
if form is None:
|
|
630
|
+
continue
|
|
631
|
+
formen.setdefault(form, []).append(rel)
|
|
632
|
+
if not formen:
|
|
633
|
+
err("Prüfung 81: kein einziger versionierter Textträger gelesen – sie hätte "
|
|
634
|
+
"nichts zu prüfen und bestünde leise (D-23)")
|
|
635
|
+
return
|
|
636
|
+
# --- Gegenstand 1: kein Traeger mischt beide Formen in sich ---------------------
|
|
637
|
+
for rel in formen.get(P81_GEMISCHT, []):
|
|
638
|
+
err(f"{rel}: mischt CRLF- und LF-Zeilen in derselben Datei. Ein gemischter "
|
|
639
|
+
f"Träger ist an keinem Arbeitsplatz richtig; er entsteht, wenn ein Werkzeug "
|
|
640
|
+
f"einzelne Zeilen in der jeweils anderen Form nachträgt (D-320, `K-81`)")
|
|
641
|
+
# --- Gegenstand 2: der Bestand traegt EINE Form ---------------------------------
|
|
642
|
+
rein = {f: n for f, n in formen.items() if f != P81_GEMISCHT}
|
|
643
|
+
if len(rein) < 2:
|
|
644
|
+
return
|
|
645
|
+
haupt = max(rein, key=lambda f: len(rein[f]))
|
|
646
|
+
for form, namen in sorted(rein.items()):
|
|
647
|
+
if form == haupt:
|
|
648
|
+
continue
|
|
649
|
+
for rel in namen:
|
|
650
|
+
err(f"{rel}: trägt {form}-Zeilenenden, während {len(rein[haupt])} von "
|
|
651
|
+
f"{sum(len(n) for n in rein.values())} versionierten Textträgern "
|
|
652
|
+
f"{haupt} tragen. Diese Prüfung schreibt keine Form vor – sie verlangt, "
|
|
653
|
+
f"daß es eine ist (D-320, `K-81`). Welche Form im Repositorium ankommt, "
|
|
654
|
+
f"setzt `.gitattributes`, nicht der Arbeitsplatz")
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
# Pruefung 82: die Bestandsliste steht auf dem Stand des Releases (CR-2026-130, D-331)
|
|
659
|
+
# ---------------------------------------------------------------------------
|
|
660
|
+
#
|
|
661
|
+
# ANLASS, UND ER IST ZWEIMAL IN ZWEI RELEASES AUFGETRETEN. `1.0.0` hat die Bestandsliste
|
|
662
|
+
# angelegt, und ihr erster Eintrag war zugleich ihr erster Befund: Beide uebernehmenden
|
|
663
|
+
# Projekte standen drei Releases hinter `main`, waehrend Kriterium 5 von D-11 als
|
|
664
|
+
# erfuellt gefuehrt wurde. `1.0.1` hat es wiederholt - die Liste stand einen halben Tag
|
|
665
|
+
# auf `1.0.0`, waehrend die Projekte `1.0.1` trugen.
|
|
666
|
+
#
|
|
667
|
+
# URSACHE IST DIE REIHENFOLGE, NICHT DIE SORGFALT. Gehoben wurde NACH dem Merge; damit
|
|
668
|
+
# war `FW-CL-11` Pruefpunkt 20 zum Merge-Zeitpunkt nicht erfuellt.
|
|
669
|
+
# ➡️ EINE LISTE, DIE ERST NACH DEM RELEASE FORTGESCHRIEBEN WIRD, IST BEIM RELEASE FALSCH.
|
|
670
|
+
#
|
|
671
|
+
# 🔴 UND SIE WAR AN ZWEI STELLEN FALSCH, NICHT AN EINER. Gemessen am 2026-09-23 vor dem
|
|
672
|
+
# ersten Handgriff dieses Releases: Das Framework hatte seine Liste auf `1.0.1`
|
|
673
|
+
# berichtigt - die AUSGELIEFERTEN Kopien in beiden uebernehmenden Projekten trugen
|
|
674
|
+
# weiter `1.0.0` neben einer VERSION `1.0.1`. Diese Pruefung waere dort rot gewesen.
|
|
675
|
+
# ➡️ WER EINE LISTE NACH DEM HEBEN FORTSCHREIBT, SCHREIBT SIE AN EINER STELLE FORT UND
|
|
676
|
+
# LIEFERT SIE AN ZWEI. Das ist der gemessene Grund, weshalb ein Verfahrensschritt allein
|
|
677
|
+
# hier nicht getragen haette.
|
|
678
|
+
#
|
|
679
|
+
# ZUSCHNITT: DIE SPALTE `Framework-Version` GEGEN `<KERN>/VERSION`. Mehr ist von hier aus
|
|
680
|
+
# nicht messbar - die Projekte liegen ausserhalb dieses Repositoriums, und eine Pruefung,
|
|
681
|
+
# die sie sucht, waere auf jedem anderen Arbeitsplatz rot (D-299).
|
|
682
|
+
#
|
|
683
|
+
# D-299-PROBE, GEFUEHRT UND BESTANDEN: In einem uebernehmenden Projekt sind Liste und
|
|
684
|
+
# VERSION beide byte-gleich aus DEMSELBEN Release ausgeliefert und tragen deshalb
|
|
685
|
+
# denselben Wert - auch dann, wenn das Projekt mehrere Releases zurueckliegt. Die
|
|
686
|
+
# Pruefung ist dort gruen, und sie braucht dafuer keine Ausnahme.
|
|
687
|
+
#
|
|
688
|
+
# 🔴 GRENZE, BENANNT: SIE MISST DIE BEHAUPTUNG, NICHT DIE TATSACHE. Wer die Zeile
|
|
689
|
+
# aendert, ohne zu heben, kommt durch. Das ist dieselbe Bauform wie bei Pruefung 77, die
|
|
690
|
+
# die VERSION des Hauptdokuments misst und nicht seinen INHALT - und sie steht hier,
|
|
691
|
+
# weil eine Grenze, die man nicht nennt, wie eine Zusage aussieht.
|
|
692
|
+
#
|
|
693
|
+
# ⚠️ PREIS, BENANNT: Jedes Release fasst diese Tabelle an - derselbe Preis wie bei
|
|
694
|
+
# Pruefung 67 und Pruefung 77.
|
|
695
|
+
P82_LISTE = KERN + "/governance/ADOPTION_REGISTRY.md"
|
|
696
|
+
P82_SPALTE = "Framework-Version"
|
|
697
|
+
P82_PROJEKTSPALTE = "Projekt"
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
def check_bestandsliste_stand(root: str) -> None:
|
|
701
|
+
"""Pruefung 82 (D-331): Die Bestandsliste nennt den Stand dieses Releases."""
|
|
702
|
+
pfad = os.path.join(root, *P82_LISTE.split("/"))
|
|
703
|
+
if not os.path.isfile(pfad):
|
|
704
|
+
err(f"{P82_LISTE}: fehlt. `RELEASE_PROCESS.md` Abschnitt 4 Punkt 4 verlangt sie "
|
|
705
|
+
f"als Nachweis der Auditierbarkeit, und Kriterium 5 von D-11 hängt an ihr "
|
|
706
|
+
f"(D-322). Prüfung 82 hätte ohne sie ihren Gegenstand verloren")
|
|
707
|
+
return
|
|
708
|
+
vpfad = os.path.join(root, KERN, "VERSION")
|
|
709
|
+
if not os.path.isfile(vpfad):
|
|
710
|
+
return # Pruefung 1 meldet die fehlende Pflichtdatei bereits
|
|
711
|
+
stand = read(vpfad).strip()
|
|
712
|
+
zeilen = read(pfad).split("\n")
|
|
713
|
+
|
|
714
|
+
# --- Den Anker suchen, und sein Fehlen als Fehler melden (D-23) -----------------
|
|
715
|
+
kopf = None
|
|
716
|
+
spalte = None
|
|
717
|
+
projekt = 0
|
|
718
|
+
for i, roh in enumerate(zeilen):
|
|
719
|
+
if not roh.lstrip().startswith("|"):
|
|
720
|
+
continue
|
|
721
|
+
zellen = tabellenzellen(roh)
|
|
722
|
+
if P82_SPALTE in zellen:
|
|
723
|
+
kopf = i
|
|
724
|
+
spalte = zellen.index(P82_SPALTE)
|
|
725
|
+
if P82_PROJEKTSPALTE in zellen:
|
|
726
|
+
projekt = zellen.index(P82_PROJEKTSPALTE)
|
|
727
|
+
break
|
|
728
|
+
if kopf is None:
|
|
729
|
+
err(f"{P82_LISTE}: keine Tabelle mit der Spalte `{P82_SPALTE}`. Prüfung 82 "
|
|
730
|
+
f"findet ihren Gegenstand über diese Überschrift; geht sie verloren, "
|
|
731
|
+
f"bestünde die Prüfung leise (D-23)")
|
|
732
|
+
return
|
|
733
|
+
|
|
734
|
+
# --- Die Zeilen des Bestands gegen VERSION halten -------------------------------
|
|
735
|
+
gemessen = 0
|
|
736
|
+
for roh in zeilen[kopf + 2:]:
|
|
737
|
+
if not roh.lstrip().startswith("|"):
|
|
738
|
+
break # eine Leerzeile beendet die Tabelle (D-264)
|
|
739
|
+
zellen = tabellenzellen(roh)
|
|
740
|
+
if len(zellen) <= spalte:
|
|
741
|
+
continue
|
|
742
|
+
wert = zellen[spalte].strip().strip("*`").strip()
|
|
743
|
+
if not wert:
|
|
744
|
+
continue
|
|
745
|
+
gemessen += 1
|
|
746
|
+
if wert == stand:
|
|
747
|
+
continue
|
|
748
|
+
name = zellen[projekt].strip() if len(zellen) > projekt else "(ohne Namen)"
|
|
749
|
+
err(f"{P82_LISTE}: {name} steht auf Framework-Version {wert}, "
|
|
750
|
+
f"{KERN}/VERSION führt {stand}. Das Heben der übernehmenden Projekte gehört "
|
|
751
|
+
f"VOR den Release-Commit (D-330); eine Liste, die erst danach "
|
|
752
|
+
f"fortgeschrieben wird, ist beim Release falsch. ⚠️ Diese Prüfung mißt die "
|
|
753
|
+
f"Behauptung der Zeile, nicht den Stand des Projekts (D-331)")
|
|
754
|
+
if not gemessen:
|
|
755
|
+
warn(f"{P82_LISTE}: die Tabelle führt keine Zeile mit einem Wert in der Spalte "
|
|
756
|
+
f"`{P82_SPALTE}`. Prüfung 82 hat nichts gemessen – das ist KEIN "
|
|
757
|
+
f"Messergebnis (D-23)")
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
# Pruefung 83: die Chronik zaehlt ihr eigenes Release zu Ende (CR-2026-131, D-335)
|
|
762
|
+
# ---------------------------------------------------------------------------
|
|
763
|
+
#
|
|
764
|
+
# ANLASS, GEMESSEN IM VORBEDINGUNGSDURCHGANG VON 1.2.0. `docs/ROADMAP.md` fuehrt je
|
|
765
|
+
# Release eine Zeile mit der SPANNE der Entscheidungen, die es vergeben hat. Ueber
|
|
766
|
+
# vierzehn Releases mit Spannenschreibweise ist sie lueckenlos - und die letzte war um
|
|
767
|
+
# zwei zu niedrig: `1.1.0` stand auf "D-329 bis D-332", vergeben sind D-329 bis D-334.
|
|
768
|
+
#
|
|
769
|
+
# DIE URSACHE IST GEMESSEN UND STEHT IM EIGENEN RELEASE. D-333 und D-334 sind BEIM
|
|
770
|
+
# UMSETZEN gefallen; die Uebergabe zu 1.1.0 sagt es woertlich. Die ROADMAP-Zeile war zu
|
|
771
|
+
# diesem Zeitpunkt laengst geschrieben.
|
|
772
|
+
# ➡️ EINE ZAHL, DIE VOR IHREM GEGENSTAND GESCHRIEBEN WIRD, IST ZUM ZEITPUNKT IHRER
|
|
773
|
+
# NIEDERSCHRIFT RICHTIG UND DANACH NICHT MEHR. Das ist die Bauform von Pruefung 40 -
|
|
774
|
+
# hier INNERHALB eines einzigen Releases statt ueber zweiundvierzig.
|
|
775
|
+
#
|
|
776
|
+
# 🔴 DER SCHWERERE TEIL: KEIN BESCHREIBENDER TRAEGER NENNT ALLE SECHS. Vier Traeger
|
|
777
|
+
# beschreiben 1.1.0 - ROADMAP vier, CHANGELOG fuenf, Antrag vier, Protokoll vier. D-333
|
|
778
|
+
# steht in keinem davon. Es steht im Register, im Protokoll und in den beiden normativen
|
|
779
|
+
# Traegern, die es GEAENDERT hat - also dort, wo es wirkt, und nirgends dort, wo das
|
|
780
|
+
# Release erklaert wird. Und D-333 ist die Entscheidung, die den SCHWERSTEN Befund von
|
|
781
|
+
# 1.1.0 behoben hat.
|
|
782
|
+
# 🟢 Der einzige Traeger, der die Menge vollstaendig nennt, ist die MARKE ("D-329 bis
|
|
783
|
+
# D-334") - und sie ist der einzige, den keine Pruefung erreichen kann: Der Markentext
|
|
784
|
+
# liegt im Tag-Objekt, nicht im Arbeitsbaum (`K-111`, `K-113`).
|
|
785
|
+
#
|
|
786
|
+
# WARUM PRUEFUNG 58 ES NICHT FAENGT. Sie haelt die Gegenrichtung - jede GENANNTE Kennung
|
|
787
|
+
# steht im Register. Der Befund hier ist eine VERGEBENE Kennung, die nirgends genannt
|
|
788
|
+
# wird.
|
|
789
|
+
# ➡️ PRUEFUNG 58 FAENGT DIE VERWAISTE NENNUNG, NICHT DIE VERWAISTE KENNUNG.
|
|
790
|
+
#
|
|
791
|
+
# D-299-PROBE, GEFUEHRT UND BESTANDEN: Beide Traeger liegen im Kern und werden
|
|
792
|
+
# byte-gleich ausgeliefert. Ein uebernehmendes Projekt, das Releases zurueckliegt, traegt
|
|
793
|
+
# dieselbe ROADMAP und dasselbe Register aus demselben Release - die Pruefung ist dort
|
|
794
|
+
# gruen und braucht keine Ausnahme.
|
|
795
|
+
#
|
|
796
|
+
# 🔴 GRENZE, BENANNT: SIE MISST DIE OBERGRENZE, NICHT DIE VOLLSTAENDIGKEIT DER
|
|
797
|
+
# NENNUNGEN. Ein Traeger, der die Spanne richtig fuehrt und D-333 im Fliesstext nicht
|
|
798
|
+
# nennt, kommt durch. Das ist dieselbe Bauform wie bei Pruefung 77 (Version, nicht
|
|
799
|
+
# Inhalt) und 82 (Behauptung, nicht Tatsache) - und sie steht hier, weil eine Grenze,
|
|
800
|
+
# die man nicht nennt, wie eine Zusage aussieht. `K-112` fuehrt die Frage weiter.
|
|
801
|
+
#
|
|
802
|
+
# ⚠️ PREIS, BENANNT: Jedes Release fasst diese Zeile an - derselbe Preis wie bei
|
|
803
|
+
# Pruefung 67, 77 und 82.
|
|
804
|
+
P83_ROADMAP = KERN + "/docs/ROADMAP.md"
|
|
805
|
+
P83_REGISTER = KERN + "/governance/DECISION_LOG.md"
|
|
806
|
+
P83_SPANNE_RE = re.compile(r"\*\*D-(\d+)\*\*\s*bis\s*\*\*D-(\d+)\*\*")
|
|
807
|
+
P83_ZEILE_RE = re.compile(r"^\|\s*(?:\*\*)?D-(\d+)", re.M)
|
|
808
|
+
P83_SONDEN_ANKER = "**Reservierter Kennungsbereich für Sonden"
|
|
809
|
+
P83_GRENZE_RE = re.compile(r"ab (\d+) zählen nicht als Obergrenze")
|
|
810
|
+
|
|
811
|
+
|
|
812
|
+
def _p83_sondengrenze(logtext: str) -> int:
|
|
813
|
+
"""Ab welcher D-Nummer eine Kennung den Sonden gehoert (D-340).
|
|
814
|
+
|
|
815
|
+
EIN BEREICH UND KEINE LISTE, und der Grund ist gemessen: Eine Liste muesste die
|
|
816
|
+
Kennung WOERTLICH nennen - und dann meldet Pruefung 58 genau diese Nennung, weil
|
|
817
|
+
sie in keiner Registerzeile steht. Eine Ausnahme, die ihren Gegenstand nennen muss,
|
|
818
|
+
um zu wirken, erzeugt den Befund, den sie verhindern soll.
|
|
819
|
+
|
|
820
|
+
NICHT dieselbe Sache wie `_synthetische_kennungen()`: Jene Menge wird nie im
|
|
821
|
+
Register gefuehrt und vom MELDEN ausgenommen; dieser Bereich wird von einer
|
|
822
|
+
Gegenprobe selbst eingetragen und muss weiterhin gemeldet werden koennen - nur als
|
|
823
|
+
OBERGRENZE zaehlt er nicht. Null heisst: der Anker ist verloren; der Aufrufer
|
|
824
|
+
meldet das.
|
|
825
|
+
"""
|
|
826
|
+
for zeile in logtext.splitlines():
|
|
827
|
+
if zeile.lstrip().startswith(P83_SONDEN_ANKER):
|
|
828
|
+
m = P83_GRENZE_RE.search(zeile)
|
|
829
|
+
return int(m.group(1)) if m else 0
|
|
830
|
+
return 0
|
|
831
|
+
|
|
832
|
+
|
|
833
|
+
def check_chronikspanne(root: str) -> None:
|
|
834
|
+
"""Pruefung 83 (D-335): Die letzte Release-Spanne endet bei der hoechsten Kennung."""
|
|
835
|
+
rpfad = os.path.join(root, *P83_ROADMAP.split("/"))
|
|
836
|
+
dpfad = os.path.join(root, *P83_REGISTER.split("/"))
|
|
837
|
+
if not os.path.isfile(rpfad):
|
|
838
|
+
err(f"{P83_ROADMAP}: fehlt - Pruefung 83 haette ihren Gegenstand verloren und "
|
|
839
|
+
f"bestuende sonst leise (D-23, D-335)")
|
|
840
|
+
return
|
|
841
|
+
if not os.path.isfile(dpfad):
|
|
842
|
+
return # Pruefung 50 und 58 melden den fehlenden Traeger bereits
|
|
843
|
+
|
|
844
|
+
dtext = read(dpfad)
|
|
845
|
+
# 🔴 DIESE PRUEFUNG BRAUCHT IHRE EIGENE AUSNAHMEMENGE, UND ZWAR EINE ANDERE ALS
|
|
846
|
+
# PRUEFUNG 50 UND 58 (D-340). Der Anlass ist gemessen und hat zwei Stufen:
|
|
847
|
+
#
|
|
848
|
+
# STUFE 1, gefunden beim ersten Abnahmelauf von 1.2.0: Die Gegenprobe 58b legt eine
|
|
849
|
+
# Registerzeile mit ihrer Sondenkennung an, und diese Pruefung las sie als hoechste -
|
|
850
|
+
# 654 gemeldete Luecken.
|
|
851
|
+
#
|
|
852
|
+
# STUFE 2, gefunden beim ZWEITEN Abnahmelauf, nachdem die Sondenkennung von Pruefung 58 in die Menge der
|
|
853
|
+
# belegten synthetischen Kennungen eingetragen war: SONDE 58a VERLOR IHREN
|
|
854
|
+
# GEGENSTAND. Pruefung 58 nimmt jene Menge vom Melden aus - und Sonde 58a prueft
|
|
855
|
+
# genau, dass diese Kennung GEMELDET wird. Das Decision Log sagt denselben Satz
|
|
856
|
+
# ueber die Sondenkennung von Pruefung 50: "sie soll ja gemeldet werden".
|
|
857
|
+
# ➡️ ZWEI PRUEFUNGEN, DIE DIESELBE KENNUNG ANSEHEN, STELLEN NICHT DIESELBE FRAGE -
|
|
858
|
+
# die eine fragt nach ZUGEHOERIGKEIT, die andere nach einer GRENZE. Das ist D-243
|
|
859
|
+
# (zwei Regeln, die einander die Voraussetzung entziehen) an einem Paar von SONDEN.
|
|
860
|
+
#
|
|
861
|
+
# Deshalb ein EIGENER Anker im selben Absatz des Decision Logs, mit eigener
|
|
862
|
+
# Begruendung. Leere Menge heisst: der Anker ist verloren - das wird gemeldet.
|
|
863
|
+
grenze = _p83_sondengrenze(dtext)
|
|
864
|
+
if not grenze:
|
|
865
|
+
err(f"{P83_REGISTER}: der Absatz '{P83_SONDEN_ANKER}…' fehlt oder nennt keine "
|
|
866
|
+
f"Bereichsgrenze. Pruefung 83 leitet ihre Ausnahme daraus ab; ohne ihn "
|
|
867
|
+
f"liest sie eine Sondenkennung als hoechste vergebene Entscheidung "
|
|
868
|
+
f"(D-23, D-340)")
|
|
869
|
+
return
|
|
870
|
+
vergeben = [int(n) for n in P83_ZEILE_RE.findall(dtext) if int(n) < grenze]
|
|
871
|
+
if not vergeben:
|
|
872
|
+
err(f"{P83_REGISTER}: keine Registerzeile '| D-NNN |' gefunden - Pruefung 83 "
|
|
873
|
+
f"findet ihren Vergleichswert dort; geht er verloren, bestuende sie leise "
|
|
874
|
+
f"(D-23, D-335)")
|
|
875
|
+
return
|
|
876
|
+
hoechste = max(vergeben)
|
|
877
|
+
|
|
878
|
+
spannen = P83_SPANNE_RE.findall(read(rpfad))
|
|
879
|
+
if not spannen:
|
|
880
|
+
err(f"{P83_ROADMAP}: keine Release-Spanne der Form '**D-NNN** bis **D-NNN**' "
|
|
881
|
+
f"gefunden. Pruefung 83 findet ihren Gegenstand ueber diese Schreibweise; "
|
|
882
|
+
f"geht sie verloren, bestuende die Pruefung leise (D-23, D-335)")
|
|
883
|
+
return
|
|
884
|
+
|
|
885
|
+
# Die hoechste Obergrenze aller Spannen - nicht die zuletzt geschriebene. Die
|
|
886
|
+
# Releasetabelle ist nicht garantiert sortiert: gemessen am 2026-09-23 stand `1.0.1`
|
|
887
|
+
# VOR `1.0.0`, und eine Pruefung, die sich auf die Reihenfolge verlaesst, misst dann
|
|
888
|
+
# die falsche Zeile (D-337).
|
|
889
|
+
obergrenze = max(int(b) for _a, b in spannen)
|
|
890
|
+
if obergrenze == hoechste:
|
|
891
|
+
return
|
|
892
|
+
if obergrenze > hoechste:
|
|
893
|
+
err(f"{P83_ROADMAP}: die hoechste Release-Spanne endet bei D-{obergrenze}, das "
|
|
894
|
+
f"Register fuehrt hoechstens D-{hoechste}. Die Chronik nennt eine "
|
|
895
|
+
f"Entscheidung, die es nicht gibt - Pruefung 58 meldet sie zusaetzlich als "
|
|
896
|
+
f"nicht gefuehrte Kennung (D-335)")
|
|
897
|
+
return
|
|
898
|
+
fehlend = ", ".join(f"D-{n}" for n in range(obergrenze + 1, hoechste + 1))
|
|
899
|
+
err(f"{P83_ROADMAP}: die hoechste Release-Spanne endet bei D-{obergrenze}, vergeben "
|
|
900
|
+
f"ist bis D-{hoechste}. In der Chronik fehlen {fehlend}. Eine Entscheidung, die "
|
|
901
|
+
f"beim Umsetzen faellt, faellt NACH der Zeile, die sie nennen soll - und eine "
|
|
902
|
+
f"Zahl, die vor ihrem Gegenstand geschrieben wird, ist danach nicht mehr richtig. "
|
|
903
|
+
f"⚠️ Diese Pruefung misst die OBERGRENZE, nicht die Vollstaendigkeit der "
|
|
904
|
+
f"Nennungen (D-335, `K-112`)")
|
|
905
|
+
|
|
906
|
+
|
|
907
|
+
# Pruefung 85: eine Zielangabe ueberlebt ihr eigenes Release nicht (CR-2026-132, D-342)
|
|
908
|
+
# ---------------------------------------------------------------------------
|
|
909
|
+
#
|
|
910
|
+
# ANLASS, GEMESSEN IM VORBEDINGUNGSDURCHGANG VON 1.3.0. `docs/ROADMAP.md` fuehrt neben
|
|
911
|
+
# der Releasetabelle Abschnitte der Form
|
|
912
|
+
# ### Geplant: <Posten> - Ziel-Release **<Version>**
|
|
913
|
+
# ALLE DREI vorhandenen nannten eine Version, die die Gegenwart ueberholt hatte:
|
|
914
|
+
# * die Umbenennung auf Koolie mit "~0.68.0" - erledigt mit 0.88.0, und der Abschnitt
|
|
915
|
+
# heisst seit fuenfzehn Releases "Geplant";
|
|
916
|
+
# * das Client Pack openai-codex mit "1.1.0" - waehrend die Releasetabelle DERSELBEN
|
|
917
|
+
# Datei ihn auf 1.3.0 fuehrt, rund 1.280 Zeilen entfernt;
|
|
918
|
+
# * die Projekt-Overlays als Installationsparameter mit "1.2.0" - ausgeliefert, und
|
|
919
|
+
# der Posten ist nicht gefahren.
|
|
920
|
+
#
|
|
921
|
+
# ➡️ EINE ZIELANGABE IST EINE ZAHL, DIE VOR IHREM GEGENSTAND GESCHRIEBEN WIRD. Das ist
|
|
922
|
+
# die Bauform von Pruefung 83, hier an der PLANSEITE derselben Datei statt an der
|
|
923
|
+
# Chronikseite - und der Beleg dafuer, dass dieselbe Bauform an zwei Enden eines
|
|
924
|
+
# Traegers auftreten kann, ohne dass die eine Pruefung die andere Stelle sieht.
|
|
925
|
+
#
|
|
926
|
+
# URSACHE GEMESSEN: Die Verschiebungen sind je einzeln ausgewiesen worden - D-127 hat
|
|
927
|
+
# den Posten auf 1.1.0 gesetzt, D-339 auf 1.3.0 -, und KEINE von ihnen hat die
|
|
928
|
+
# Ueberschrift angefasst, weil die Releasetabelle als der eine Ort galt.
|
|
929
|
+
# ➡️ WER EINE ZAHL AN ZWEI STELLEN FUEHRT, PFLEGT EINE.
|
|
930
|
+
#
|
|
931
|
+
# D-299-PROBE, GEFUEHRT UND BESTANDEN: Beide Traeger - ROADMAP und VERSION - liegen im
|
|
932
|
+
# Kern und werden byte-gleich ausgeliefert. Ein uebernehmendes Projekt, das Releases
|
|
933
|
+
# zurueckliegt, traegt beide aus demselben Release; die Pruefung ist dort gruen und
|
|
934
|
+
# braucht keine Ausnahme.
|
|
935
|
+
#
|
|
936
|
+
# 🔴 GRENZE, BENANNT: SIE MISST DIE ZIELANGABE, NICHT DEN STAND DES POSTENS. Ein
|
|
937
|
+
# Abschnitt, dessen Ziel in der Zukunft liegt, kann laengst erledigt sein und kommt
|
|
938
|
+
# durch - dieselbe Bauform wie Pruefung 77 (Version, nicht Inhalt) und 82 (Behauptung,
|
|
939
|
+
# nicht Tatsache). Sie steht hier, weil eine Grenze, die man nicht nennt, wie eine
|
|
940
|
+
# Zusage aussieht; `K-116` fuehrt die Frage weiter.
|
|
941
|
+
#
|
|
942
|
+
# ⚠️ PREIS, BENANNT: Wer einen Posten verschiebt, fasst die Ueberschrift an - und genau
|
|
943
|
+
# das ist der Zweck. Es ist derselbe Preis wie bei Pruefung 67, 77, 82 und 83, nur faellt
|
|
944
|
+
# er hier nicht je Release an, sondern je Verschiebung.
|
|
945
|
+
P85_ROADMAP = KERN + "/docs/ROADMAP.md"
|
|
946
|
+
P85_UEBERSCHRIFT = "### Geplant:"
|
|
947
|
+
P85_ZIEL_RE = re.compile(r"Ziel-Release\s*\**\s*`?~?(\d+)\.(\d+)\.(\d+)`?")
|
|
948
|
+
|
|
949
|
+
|
|
950
|
+
def _p85_version(text: str) -> tuple[int, int, int] | None:
|
|
951
|
+
"""Die drei Zahlen einer Versionsangabe - oder None."""
|
|
952
|
+
m = re.match(r"\s*(\d+)\.(\d+)\.(\d+)\s*$", text)
|
|
953
|
+
return (int(m.group(1)), int(m.group(2)), int(m.group(3))) if m else None
|
|
954
|
+
|
|
955
|
+
|
|
956
|
+
def check_zielangabe(root: str) -> None:
|
|
957
|
+
"""Pruefung 85 (D-342): Ein Planabschnitt nennt kein erreichtes Ziel-Release."""
|
|
958
|
+
rpfad = os.path.join(root, *P85_ROADMAP.split("/"))
|
|
959
|
+
vpfad = os.path.join(root, KERN, "VERSION")
|
|
960
|
+
if not os.path.isfile(rpfad):
|
|
961
|
+
err(f"{P85_ROADMAP}: fehlt - Pruefung 85 haette ihren Gegenstand verloren und "
|
|
962
|
+
f"bestuende sonst leise (D-23, D-342)")
|
|
963
|
+
return
|
|
964
|
+
if not os.path.isfile(vpfad):
|
|
965
|
+
return # Pruefung 1 meldet die fehlende Pflichtdatei bereits
|
|
966
|
+
stand = _p85_version(read(vpfad))
|
|
967
|
+
if stand is None:
|
|
968
|
+
return # Pruefung 67 meldet eine unlesbare VERSION bereits
|
|
969
|
+
|
|
970
|
+
ueberschriften = [z for z in read(rpfad).splitlines()
|
|
971
|
+
if z.startswith(P85_UEBERSCHRIFT)]
|
|
972
|
+
if not ueberschriften:
|
|
973
|
+
err(f"{P85_ROADMAP}: keine Ueberschrift '{P85_UEBERSCHRIFT} …' gefunden. "
|
|
974
|
+
f"Pruefung 85 findet ihren Gegenstand ueber diese Schreibweise; geht sie "
|
|
975
|
+
f"verloren, bestuende die Pruefung leise (D-23, D-342)")
|
|
976
|
+
return
|
|
977
|
+
|
|
978
|
+
# 🔴 DER ANKER IST ZWEITEILIG, UND BEIDE TEILE WERDEN GEMELDET. Eine Ueberschrift
|
|
979
|
+
# OHNE Zielangabe ist kein stiller Durchlauf, sondern der billigste Weg, diese
|
|
980
|
+
# Pruefung loszuwerden - genau die Bauform, die D-124 mit "ein Posten ohne Zahl
|
|
981
|
+
# bleibt lange liegen" bereits einmal entschieden hat.
|
|
982
|
+
ohne_ziel = [z for z in ueberschriften if not P85_ZIEL_RE.search(z)]
|
|
983
|
+
if ohne_ziel:
|
|
984
|
+
err(f"{P85_ROADMAP}: {len(ohne_ziel)} Planabschnitt(e) nennen kein "
|
|
985
|
+
f"Ziel-Release: {'; '.join(z[:70] for z in ohne_ziel)}. Ein Posten ohne "
|
|
986
|
+
f"Zahl bleibt in diesem Projekt erfahrungsgemaess lange liegen (D-124) - "
|
|
987
|
+
f"und er entzieht sich zugleich dieser Pruefung (D-342)")
|
|
988
|
+
|
|
989
|
+
for zeile in ueberschriften:
|
|
990
|
+
m = P85_ZIEL_RE.search(zeile)
|
|
991
|
+
if not m:
|
|
992
|
+
continue
|
|
993
|
+
ziel = (int(m.group(1)), int(m.group(2)), int(m.group(3)))
|
|
994
|
+
if ziel > stand:
|
|
995
|
+
continue
|
|
996
|
+
err(f"{P85_ROADMAP}: der Abschnitt '{zeile[:70]}…' nennt das Ziel-Release "
|
|
997
|
+
f"{m.group(1)}.{m.group(2)}.{m.group(3)}, und "
|
|
998
|
+
f"{'.'.join(str(n) for n in stand)} ist erreicht. Entweder ist der Posten "
|
|
999
|
+
f"gefahren - dann ist er nicht mehr 'Geplant' - oder er ist ueberfaellig "
|
|
1000
|
+
f"und braucht eine neue Zahl. ➡️ Eine Zielangabe ist eine Zahl, die vor "
|
|
1001
|
+
f"ihrem Gegenstand geschrieben wird. ⚠️ Diese Pruefung misst die "
|
|
1002
|
+
f"ZIELANGABE, nicht den STAND des Postens (D-342, `K-116`)")
|
|
1003
|
+
|
|
1004
|
+
# ---------------------------------------------------------------------------
|
|
1005
|
+
#
|
|
1006
|
+
# ANLASS. 1.9.0 ist das Qualitaetssicherungsrelease der Dokumentation (D-370). Seine
|
|
1007
|
+
# Vorbedingung war, VOR der Durchsicht festzulegen, welche Dokumente es gibt, was je
|
|
1008
|
+
# Dokument "in Ordnung" heisst - und was davon eine Maschine pruefen kann. Sonst ist
|
|
1009
|
+
# derselbe Befund in drei Releases wieder da: Die Standueberschrift der Roadmap stand
|
|
1010
|
+
# bei 1.8.0 vier Releases zurueck, direkt ueber dem Satz "Wird mit jedem Release
|
|
1011
|
+
# fortgeschrieben".
|
|
1012
|
+
#
|
|
1013
|
+
# DIE DOKUMENTKLASSEN STEHEN HIER, AN EINER STELLE (D-371), und
|
|
1014
|
+
# docs/DOCUMENTATION_STANDARD.md beschreibt sie, statt sie ein zweites Mal aufzuzaehlen:
|
|
1015
|
+
# A Einstieg - wer das Framework zum ersten Mal liest
|
|
1016
|
+
# B Regeln - was gilt (Core-Module, Laufzeit, Prozesse, Checklisten, Skills ...)
|
|
1017
|
+
# C Register - Belege und Verzeichnisse; ihr Inhalt wird nicht umgeschrieben
|
|
1018
|
+
# D Hauptdokument - die Kapitelquellen unter build/doc/
|
|
1019
|
+
# Die Nachweisschicht (clientmap.NACHWEIS_ABLAGEN) ist keine Klasse - mit einer
|
|
1020
|
+
# Ausnahme: build/doc/ liegt darin, weil build/ nicht zur Nutzung gehoert, ist aber
|
|
1021
|
+
# das Hauptdokument und damit Klasse D.
|
|
1022
|
+
#
|
|
1023
|
+
# D-299: Alle vier Pruefungen lesen Traeger, die byte-gleich in jedes Projekt
|
|
1024
|
+
# geliefert werden - dort sind sie so gruen wie hier. Die Wurzel-README gehoert dem
|
|
1025
|
+
# Quellrepositorium; in einem Projekt gehoert die Wurzel dem Projekt, und sie wird
|
|
1026
|
+
# dort nicht gelesen. Fehlt build/doc/ (Lieferumfang "nutzung"), fehlt Klasse D.
|
|
1027
|
+
DOK_REGISTER = frozenset({
|
|
1028
|
+
"CHANGELOG.md", "governance/DECISION_LOG.md", "docs/ROADMAP.md",
|
|
1029
|
+
"tests/TEST_CATALOG.md", "tests/EDGE_CASES.md", "docs/PLACEHOLDER_REGISTRY.md",
|
|
1030
|
+
"governance/ADOPTION_REGISTRY.md",
|
|
1031
|
+
})
|
|
1032
|
+
DOK_REGISTER_RE = re.compile(r"skills/[^/]+/(?:TESTS|EXAMPLES|CHANGELOG)\.md$")
|
|
1033
|
+
DOK_EINSTIEG = ("onboarding/", "examples/", "pilot/", "docs/ADOPTION_GUIDE.md",
|
|
1034
|
+
"docs/RUNTIME_GLOSSARY.md", "clients/README.md")
|
|
1035
|
+
DOK_EINSTIEG_RE = re.compile(r"clients/[^_/][^/]*/CLIENT_PACK\.md$")
|
|
1036
|
+
DOK_NACHWEIS = ("governance/change-requests/", "tests/protocols/", "tests/erhebungen/",
|
|
1037
|
+
"build/")
|
|
1038
|
+
def dokumentklasse(rel: str) -> str | None:
|
|
1039
|
+
"""Die Klasse eines Dokuments nach D-371 - projektrelativ, mit '/'. None heisst:
|
|
1040
|
+
kein Dokument dieser Pruefungen (keine Markdown-Datei, Nachweisschicht, Projekt)."""
|
|
1041
|
+
if not rel.endswith(".md"):
|
|
1042
|
+
return None
|
|
1043
|
+
if not rel.startswith(KERN + "/"):
|
|
1044
|
+
return "A" if rel in DOK_WURZEL else None
|
|
1045
|
+
k = rel[len(KERN) + 1:]
|
|
1046
|
+
if k.startswith("build/doc/"):
|
|
1047
|
+
return "D"
|
|
1048
|
+
if k.startswith(DOK_NACHWEIS):
|
|
1049
|
+
return None
|
|
1050
|
+
if k in DOK_REGISTER or DOK_REGISTER_RE.search(k):
|
|
1051
|
+
return "C"
|
|
1052
|
+
if k.startswith(DOK_EINSTIEG) or DOK_EINSTIEG_RE.match(k):
|
|
1053
|
+
return "A"
|
|
1054
|
+
return "B"
|
|
1055
|
+
|
|
1056
|
+
|
|
1057
|
+
def _dokumente(root: str):
|
|
1058
|
+
"""(rel, klasse) aller Dokumente dieses Baums, sortiert."""
|
|
1059
|
+
gefunden = []
|
|
1060
|
+
kern = os.path.join(root, KERN)
|
|
1061
|
+
for dirpath, dirnames, filenames in os.walk(kern):
|
|
1062
|
+
dirnames[:] = sorted(d for d in dirnames if d not in (".git", "__pycache__", "out"))
|
|
1063
|
+
for fn in filenames:
|
|
1064
|
+
rel = os.path.relpath(os.path.join(dirpath, fn), root).replace(os.sep, "/")
|
|
1065
|
+
k = dokumentklasse(rel)
|
|
1066
|
+
if k:
|
|
1067
|
+
gefunden.append((rel, k))
|
|
1068
|
+
if ist_quellrepositorium(root):
|
|
1069
|
+
gefunden += [(rel, "A") for rel in DOK_WURZEL if os.path.isfile(os.path.join(root, rel))]
|
|
1070
|
+
return sorted(gefunden)
|
|
1071
|
+
|
|
1072
|
+
|
|
1073
|
+
DOK_ZAUN_RE = re.compile(r"^\s*(`{3,}|~{3,})")
|
|
1074
|
+
|
|
1075
|
+
|
|
1076
|
+
def _ohne_code(text: str) -> tuple[list[str], bool]:
|
|
1077
|
+
"""Die Zeilen ohne Codebloecke und Inline-Code - Zeilennummern bleiben erhalten.
|
|
1078
|
+
Zweiter Wert: Ist am Ende ein Codeblock offen?
|
|
1079
|
+
|
|
1080
|
+
Code ist ZITAT: ein Befehl, eine Ausgabe, eine Meldung, die woertlich so lautet.
|
|
1081
|
+
Eine Rechtschreib- oder Formpruefung darin pruefte den zitierten Gegenstand und
|
|
1082
|
+
nicht das Dokument."""
|
|
1083
|
+
zeilen, zaun = [], ""
|
|
1084
|
+
for z in text.split("\n"):
|
|
1085
|
+
m = DOK_ZAUN_RE.match(z)
|
|
1086
|
+
if m:
|
|
1087
|
+
if not zaun:
|
|
1088
|
+
zaun = m.group(1)[0] * 3
|
|
1089
|
+
elif m.group(1).startswith(zaun):
|
|
1090
|
+
zaun = ""
|
|
1091
|
+
zeilen.append("")
|
|
1092
|
+
continue
|
|
1093
|
+
zeilen.append("" if zaun else re.sub(r"`[^`\n]*`", "``", z))
|
|
1094
|
+
return zeilen, bool(zaun)
|
|
1095
|
+
|
|
1096
|
+
|
|
1097
|
+
def _frontmatter_ende(zeilen: list[str]) -> int:
|
|
1098
|
+
if zeilen and zeilen[0].strip() == "---":
|
|
1099
|
+
for i in range(1, len(zeilen)):
|
|
1100
|
+
if zeilen[i].strip() == "---":
|
|
1101
|
+
return i + 1
|
|
1102
|
+
return 0
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
# --- Pruefung 92: die Rechtschreibung (D-373) ----------------------------------------
|
|
1106
|
+
#
|
|
1107
|
+
# ANLASS, gemessen im Vorbedingungsdurchgang von 1.9.0: 603 Woerter in der Schreibung
|
|
1108
|
+
# vor 1996 gegen 1.192 in der geltenden, und NEUNZEHN Dokumente mischten beide - oft im
|
|
1109
|
+
# selben Absatz ("dass" neben "daß"). Die Klassen A, B und D schreiben nach dem
|
|
1110
|
+
# geltenden Duden; die Register (C) bleiben, wie sie geschrieben wurden (D-371): Ein
|
|
1111
|
+
# Beleg wird nicht umgeschrieben, auch nicht orthographisch.
|
|
1112
|
+
# WIE: eine feste Liste der Staemme, in denen das "ß" nach kurzem Vokal steht und
|
|
1113
|
+
# deshalb heute "ss" ist. Ein allgemeines "ß nach kurzem Vokal" kann keine Maschine
|
|
1114
|
+
# ohne Woerterbuch entscheiden ("Maß" gegen "Meß"); eine Liste kann es fuer die Woerter,
|
|
1115
|
+
# die hier vorkommen.
|
|
1116
|
+
# GRENZE: Ein Wort, das nicht auf der Liste steht, kommt durch. Die Liste ist aus dem
|
|
1117
|
+
# gemessenen Bestand gezogen (308 verschiedene Woerter mit "ß", 2026-09-25), nicht aus
|
|
1118
|
+
# einem Woerterbuch. Code (Bloecke und Inline) ist Zitat und wird nicht geprueft.
|
|
1119
|
+
P92_ALT_RE = re.compile(
|
|
1120
|
+
r"\b(?:[Dd]aß|\w*[Mm]uß\w*|\w*[Mm]üßt\w*|\w*[Mm]iß(?:t|\w)\w*|\w*[Mm]eß\w*|\w*MEß\w*|"
|
|
1121
|
+
r"\w*[Ll]äßt\w*|\w*[Vv]erläßlich\w*|\w*[Ff]aß(?:t|te|ten|bar)\w*|\w*[Pp]aß(?:t|te|ten)?\b|"
|
|
1122
|
+
r"\w*[Ll]aß\b|\w*[Ll]aß(?:fall|t)\w*|\w*[Ww][uü]ß(?:t|te|ten)\w*|\w*[Ss]chluß\w*|"
|
|
1123
|
+
r"\w*[Vv]ergi?ß(?:t|lich\w*)|\w*[Vv]ergeß\w*|\w*[Pp]rozeß\w*|\b[Bb]iß\b|\b[Rr]iß\b|"
|
|
1124
|
+
r"\w*[Ff]luß\w*|\w*[Ss]chuß\w*|\w*[Ee]ngpaß)")
|
|
1125
|
+
|
|
1126
|
+
|
|
1127
|
+
def check_rechtschreibung(root: str) -> None:
|
|
1128
|
+
"""Pruefung 92 (D-373): Klassen A, B und D ohne Schreibung vor 1996."""
|
|
1129
|
+
for rel, klasse in _dokumente(root):
|
|
1130
|
+
if klasse == "C":
|
|
1131
|
+
continue
|
|
1132
|
+
zeilen, _ = _ohne_code(read(os.path.join(root, *rel.split("/"))))
|
|
1133
|
+
funde = [f"{i + 1}: {w}" for i, z in enumerate(zeilen) for w in P92_ALT_RE.findall(z)]
|
|
1134
|
+
if funde:
|
|
1135
|
+
err(f"{rel}: {len(funde)} Wort/Wörter in der Schreibung vor 1996 "
|
|
1136
|
+
f"({'; '.join(funde[:6])}{' …' if len(funde) > 6 else ''}). Klasse "
|
|
1137
|
+
f"{klasse} schreibt nach dem geltenden Duden: 'dass', 'muss', 'misst', "
|
|
1138
|
+
f"'Messbaum' (D-373)")
|
|
1139
|
+
|
|
1140
|
+
|
|
1141
|
+
# --- Pruefung 93: die Form (D-374) ---------------------------------------------------
|
|
1142
|
+
#
|
|
1143
|
+
# Vier Gegenstaende, alle in jedem Dokument der Klassen A bis D:
|
|
1144
|
+
# (a) jeder Codeblock ist geschlossen - ein offener verschluckt den Rest der Datei,
|
|
1145
|
+
# und die Assemblierung des Hauptdokuments bricht an genau dieser Stelle;
|
|
1146
|
+
# (b) genau eine Hauptueberschrift ('# '); mit YAML-Frontmatter hoechstens eine,
|
|
1147
|
+
# denn dort traegt der Kopf den Namen;
|
|
1148
|
+
# (c) keine uebersprungene Ueberschriftenebene ('##' auf '####');
|
|
1149
|
+
# (d) jede Tabellenzeile hat die Spaltenzahl ihrer Kopfzeile - ein ungeschuetzter
|
|
1150
|
+
# senkrechter Strich verschiebt jede Zelle rechts davon, und der Leser sieht es
|
|
1151
|
+
# nicht, weil die Tabelle trotzdem rendert.
|
|
1152
|
+
# ANLASS: Gemessen im Vorbedingungsdurchgang war der Bestand bis auf EINE Datei sauber
|
|
1153
|
+
# (ein Agentenprofil mit drei Hauptueberschriften). Die Pruefung ist deshalb ein
|
|
1154
|
+
# Waechter und kein Aufraeumen - und genau so billig soll sie bleiben.
|
|
1155
|
+
# GRENZE: Sie prueft die Gestalt, nicht die Gliederung - ob die Ueberschriften das
|
|
1156
|
+
# Richtige gliedern, bleibt Durchsicht.
|
|
1157
|
+
def _tabellenzellen(zeile: str) -> int:
|
|
1158
|
+
z = re.sub(r"`[^`]*`", "C", zeile).replace("\\|", "x").strip()
|
|
1159
|
+
if z.startswith("|"):
|
|
1160
|
+
z = z[1:]
|
|
1161
|
+
if z.endswith("|"):
|
|
1162
|
+
z = z[:-1]
|
|
1163
|
+
return len(z.split("|"))
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
def check_dokumentform(root: str) -> None:
|
|
1167
|
+
"""Pruefung 93 (D-374): Codebloecke, Hauptueberschrift, Ebenen, Tabellenspalten."""
|
|
1168
|
+
for rel, _klasse in _dokumente(root):
|
|
1169
|
+
text = read(os.path.join(root, *rel.split("/")))
|
|
1170
|
+
roh = text.split("\n")
|
|
1171
|
+
zeilen, offen = _ohne_code(text)
|
|
1172
|
+
if offen:
|
|
1173
|
+
err(f"{rel}: ein Codeblock ist bis zum Dateiende nicht geschlossen (D-374)")
|
|
1174
|
+
continue
|
|
1175
|
+
fm = _frontmatter_ende(roh)
|
|
1176
|
+
h1 = sum(1 for i, z in enumerate(zeilen) if i >= fm and z.startswith("# "))
|
|
1177
|
+
if (fm and h1 > 1) or (not fm and h1 != 1):
|
|
1178
|
+
err(f"{rel}: {h1} Hauptüberschriften ('# '), erwartet "
|
|
1179
|
+
f"{'höchstens eine (mit Frontmatter)' if fm else 'genau eine'} (D-374)")
|
|
1180
|
+
ebene = 0
|
|
1181
|
+
for i, z in enumerate(zeilen):
|
|
1182
|
+
m = re.match(r"(#{1,6}) ", z)
|
|
1183
|
+
if not m:
|
|
1184
|
+
continue
|
|
1185
|
+
n = len(m.group(1))
|
|
1186
|
+
if ebene and n > ebene + 1:
|
|
1187
|
+
err(f"{rel}:{i + 1}: Überschrift der Ebene {n} direkt unter Ebene "
|
|
1188
|
+
f"{ebene} – eine Ebene ist übersprungen (D-374)")
|
|
1189
|
+
ebene = n
|
|
1190
|
+
i = 0
|
|
1191
|
+
while i < len(zeilen) - 1:
|
|
1192
|
+
if (zeilen[i].lstrip().startswith("|")
|
|
1193
|
+
and re.match(r"\s*\|?\s*:?-{3,}", zeilen[i + 1])):
|
|
1194
|
+
soll = _tabellenzellen(zeilen[i])
|
|
1195
|
+
j = i + 2
|
|
1196
|
+
while j < len(zeilen) and zeilen[j].lstrip().startswith("|"):
|
|
1197
|
+
ist = _tabellenzellen(zeilen[j])
|
|
1198
|
+
if ist != soll:
|
|
1199
|
+
err(f"{rel}:{j + 1}: Tabellenzeile mit {ist} statt {soll} "
|
|
1200
|
+
f"Spalten – ein ungeschützter senkrechter Strich verschiebt "
|
|
1201
|
+
f"jede Zelle rechts davon (D-374)")
|
|
1202
|
+
j += 1
|
|
1203
|
+
i = j
|
|
1204
|
+
else:
|
|
1205
|
+
i += 1
|
|
1206
|
+
|
|
1207
|
+
|
|
1208
|
+
# --- Pruefung 94: der Steckbrief (D-375) ---------------------------------------------
|
|
1209
|
+
#
|
|
1210
|
+
# Ein Dokument der Klassen A und B traegt vor seinem ersten Abschnitt einen Steckbrief
|
|
1211
|
+
# (Tabelle "| Attribut | Wert |") mit einer Kennung (ID oder <Art>-ID), einer Version und
|
|
1212
|
+
# einem Status. Pruefung 13 prueft die FORM eines Versionsfeldes, das da ist; dass es da
|
|
1213
|
+
# ist, prueft sie nicht - und 116 von 215 Dokumenten hatten keines.
|
|
1214
|
+
# AUSGENOMMEN, jeweils mit Grund:
|
|
1215
|
+
# - README.md: ein Verzeichnis, kein Dokument mit eigenem Stand; ebenso die
|
|
1216
|
+
# Einstiegsdokumente der Wurzel (DOK_WURZEL, D-437) - sie tragen ihren Stand ueber
|
|
1217
|
+
# VERSION und verweisen auf die Dokumente, die einen Steckbrief tragen;
|
|
1218
|
+
# - die Laufzeitschicht (framework/runtime/, role-packs/*/runtime/, root-template/):
|
|
1219
|
+
# sie wird so in die Sitzung geladen, und ihre Laenge ist begrenzt (Pruefung 4);
|
|
1220
|
+
# - Ausfuellvorlagen (templates/, Musterdokumente der Overlay-Muster, der
|
|
1221
|
+
# Antragsvorlage, die Abbildungsvorlage der Organisationsvorgaben): Sie werden
|
|
1222
|
+
# kopiert und gehoeren danach dem Projekt - ein Steckbrief des Frameworks darin
|
|
1223
|
+
# waere eine falsche Herkunftsangabe;
|
|
1224
|
+
# - examples/: Beispielausgaben, deren Gestalt die eines Ergebnisses ist.
|
|
1225
|
+
# GRENZE: Sie prueft die ANWESENHEIT der drei Zeilen; ihren Wert prueft Pruefung 13
|
|
1226
|
+
# (Version) und Pruefung 55 (Status).
|
|
1227
|
+
P94_AUSNAHMEN = ("framework/runtime/", "templates/", "examples/")
|
|
1228
|
+
P94_AUSNAHMEN_RE = re.compile(
|
|
1229
|
+
r"(?:^|/)README\.md$|^framework/role-packs/[^/]+/runtime/|^clients/[^/]+/root-template/|"
|
|
1230
|
+
r"^framework/overlay-patterns/[^/]+/documents/|^governance/CHANGE_REQUEST_TEMPLATE\.md$|"
|
|
1231
|
+
r"^framework/org-policies/MAPPING_CLASSIFICATION\.md$")
|
|
1232
|
+
P94_KOPF = "| Attribut | Wert |"
|
|
1233
|
+
|
|
1234
|
+
|
|
1235
|
+
def check_steckbrief(root: str) -> None:
|
|
1236
|
+
"""Pruefung 94 (D-375): Klassen A und B tragen ID, Version und Status."""
|
|
1237
|
+
for rel, klasse in _dokumente(root):
|
|
1238
|
+
if klasse not in "AB" or rel in DOK_WURZEL:
|
|
1239
|
+
continue
|
|
1240
|
+
k = rel[len(KERN) + 1:]
|
|
1241
|
+
if k.startswith(P94_AUSNAHMEN) or P94_AUSNAHMEN_RE.search(k):
|
|
1242
|
+
continue
|
|
1243
|
+
zeilen = read(os.path.join(root, *rel.split("/"))).split("\n")
|
|
1244
|
+
kopf = []
|
|
1245
|
+
for i, z in enumerate(zeilen):
|
|
1246
|
+
if z.startswith("## "):
|
|
1247
|
+
break
|
|
1248
|
+
if re.sub(r"\s+", " ", z.strip()) == P94_KOPF:
|
|
1249
|
+
j = i + 2
|
|
1250
|
+
kopf = []
|
|
1251
|
+
while j < len(zeilen) and zeilen[j].startswith("|"):
|
|
1252
|
+
kopf.append(zeilen[j])
|
|
1253
|
+
j += 1
|
|
1254
|
+
break
|
|
1255
|
+
fehlt = [name for name, rx in (
|
|
1256
|
+
("ID", r"^\|\s*(?:[\w-]+-)?ID\s*\|"), ("Version", r"^\|\s*Version\b[^|]*\|"),
|
|
1257
|
+
("Status", r"^\|\s*Status\s*\|")) if not any(re.match(rx, z) for z in kopf)]
|
|
1258
|
+
if fehlt:
|
|
1259
|
+
err(f"{rel}: {'kein Steckbrief' if not kopf else 'Steckbrief ohne ' + ', '.join(fehlt)} "
|
|
1260
|
+
f"vor dem ersten Abschnitt. Klasse {klasse} trägt eine Tabelle "
|
|
1261
|
+
f"'{P94_KOPF}' mit Kennung, Version und Status – sonst unterscheidet das "
|
|
1262
|
+
f"Dokument keine zwei Stände (D-375)")
|