feat(ITC-WP-0016): establish PracticePattern language
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a025c2-407a-7a32-b40a-f37a52f03f62
This commit is contained in:
tegwick 2026-08-21 22:22:46 +02:00
parent 5e2435aaf9
commit 149d2ced70
27 changed files with 1119 additions and 99 deletions

View file

@ -39,6 +39,8 @@ RETRIEVAL_ARTIFACT_KINDS = {
"model-selection-guide",
"native-concept-map",
"pattern",
"practice-pattern",
"practice-pattern-scheme",
"profile-alignment",
"profile",
"standard",
@ -46,6 +48,14 @@ RETRIEVAL_ARTIFACT_KINDS = {
}
CONSUMER_BRIEF_IDS = ("user-engine", "railiance-fabric", "repo-scoping")
COMMON_DISTINCTIONS = [
{
"id": "interface-deprecation-retirement-removal",
"title": "Interface deprecation vs retirement vs removal",
"summary": "Deprecation guides and observes callers, retirement ends legacy behavior while retaining a metered tombstone, and removal deletes that tombstone only after the evidence gate passes.",
"source_artifacts": [
"practice-pattern/interface-deprecation-strangler",
],
},
{
"id": "actor-subject-principal",
"title": "Actor vs Subject vs Principal",
@ -934,6 +944,10 @@ def _summary_for_artifact(artifact: Any) -> str:
return f"Native source concept map for assimilation or benchmark work: {artifact.title}."
if artifact.kind == "pattern":
return f"Reusable canon pattern: {artifact.title}."
if artifact.kind == "practice-pattern":
return f"Reusable canon PracticePattern: {artifact.title}."
if artifact.kind == "practice-pattern-scheme":
return f"Contract for canon PracticePattern artifacts: {artifact.title}."
if artifact.kind == "profile-alignment":
return f"Profile-specific evaluation alignment artifact: {artifact.title}."
if artifact.kind == "visualization-example-set":

View file

@ -1,6 +1,7 @@
from __future__ import annotations
from pathlib import Path
import re
from typing import Any
import yaml
@ -54,6 +55,7 @@ REQUIRED_SCHEMAS = (
"capability.schema.yaml",
"capability-record.schema.yaml",
"attribute-value-type.schema.yaml",
"practice-pattern.schema.yaml",
)
RETRIEVAL_BRIEF_KINDS = {
@ -85,6 +87,8 @@ RETRIEVAL_BRIEF_KINDS = {
"model-selection-guide",
"native-concept-map",
"pattern",
"practice-pattern",
"practice-pattern-scheme",
"profile-alignment",
"profile",
"standard",
@ -348,6 +352,43 @@ ALIGNMENT_REVIEW_TEMPLATE_MARKERS = {
"## Canon Feedback",
}
PRACTICE_PATTERN_REQUIRED_FRONTMATTER = {
"id",
"title",
"type",
"scheme",
"status",
"version",
"summary",
}
PRACTICE_PATTERN_STATUSES = {
"draft",
"candidate",
"active",
"deprecated",
"retired",
}
PRACTICE_PATTERN_REQUIRED_HEADINGS = {
"## Intent",
"## Context",
"## Problem",
"## Forces",
"## Solution",
"## Dynamics",
"## Invariants",
"## Evidence",
"## Consequences",
"## Known Uses",
}
PRACTICE_PATTERN_ID_RE = re.compile(
r"^practice-pattern/[a-z0-9]+(?:-[a-z0-9]+)*$"
)
PRACTICE_PATTERN_TITLE_RE = re.compile(r"^[A-Z][A-Za-z0-9]*$")
PRACTICE_PATTERN_VERSION_RE = re.compile(r"^[0-9]+\.[0-9]+(?:\.[0-9]+)?$")
def structural_checks(context: Any) -> dict[str, list[dict[str, Any]]]:
errors: list[dict[str, Any]] = []
@ -359,6 +400,11 @@ def structural_checks(context: Any) -> dict[str, list[dict[str, Any]]]:
_check_capability_catalog(errors)
_check_canon_paths(context.repo_root, context.infospace_root, errors)
_check_artifact_index(context.repo_root, context.infospace_root, errors)
_check_practice_pattern_assets(
context.infospace_root,
context.infospace.artifacts,
errors,
)
_check_agent_assets(context.infospace_root, context.infospace.artifacts, errors)
_check_purpose_demand_assets(context.infospace_root, context.infospace.artifacts, errors)
_check_user_engine_evaluation_assets(
@ -391,6 +437,140 @@ def structural_checks(context: Any) -> dict[str, list[dict[str, Any]]]:
return {"errors": errors, "warnings": warnings}
def _check_practice_pattern_assets(
infospace_root: Path,
artifacts: list[Any],
errors: list[dict[str, Any]],
) -> None:
for artifact in artifacts:
if artifact.kind != "practice-pattern":
continue
path = infospace_root / artifact.path
frontmatter = _read_markdown_frontmatter(path, errors)
missing_fields = sorted(
PRACTICE_PATTERN_REQUIRED_FRONTMATTER - set(frontmatter)
)
if missing_fields:
errors.append(
{
"code": "practice_pattern_missing_frontmatter",
"artifact_id": artifact.id,
"path": artifact.path,
"fields": missing_fields,
}
)
expected = {
"id": artifact.id,
"title": artifact.title,
"type": "practice-pattern",
"scheme": "practice-pattern/0.1",
}
for field, value in expected.items():
if frontmatter.get(field) != value:
errors.append(
{
"code": "practice_pattern_frontmatter_mismatch",
"artifact_id": artifact.id,
"path": artifact.path,
"field": field,
"expected": value,
"actual": frontmatter.get(field),
}
)
status = frontmatter.get("status")
if status not in PRACTICE_PATTERN_STATUSES:
errors.append(
{
"code": "practice_pattern_invalid_status",
"artifact_id": artifact.id,
"path": artifact.path,
"status": status,
}
)
scalar_contracts = (
("id", PRACTICE_PATTERN_ID_RE),
("title", PRACTICE_PATTERN_TITLE_RE),
("version", PRACTICE_PATTERN_VERSION_RE),
)
for field, pattern in scalar_contracts:
value = frontmatter.get(field)
if not isinstance(value, str) or pattern.fullmatch(value) is None:
errors.append(
{
"code": "practice_pattern_invalid_frontmatter_value",
"artifact_id": artifact.id,
"path": artifact.path,
"field": field,
"value": value,
}
)
summary = frontmatter.get("summary")
if not isinstance(summary, str) or not summary.strip():
errors.append(
{
"code": "practice_pattern_invalid_frontmatter_value",
"artifact_id": artifact.id,
"path": artifact.path,
"field": "summary",
"value": summary,
}
)
for field in ("aliases", "uses", "related_patterns", "known_uses"):
value = frontmatter.get(field, [])
if not isinstance(value, list) or not all(
isinstance(item, str) for item in value
):
errors.append(
{
"code": "practice_pattern_invalid_frontmatter_value",
"artifact_id": artifact.id,
"path": artifact.path,
"field": field,
"value": value,
}
)
related_patterns = frontmatter.get("related_patterns", [])
if isinstance(related_patterns, list):
for related in related_patterns:
if isinstance(related, str) and not related.startswith(
"practice-pattern/"
):
errors.append(
{
"code": "practice_pattern_invalid_related_pattern",
"artifact_id": artifact.id,
"path": artifact.path,
"value": related,
}
)
try:
headings = {
line.strip()
for line in path.read_text(encoding="utf-8").splitlines()
if line.startswith("## ")
}
except FileNotFoundError:
continue
missing_headings = sorted(PRACTICE_PATTERN_REQUIRED_HEADINGS - headings)
if missing_headings:
errors.append(
{
"code": "practice_pattern_missing_sections",
"artifact_id": artifact.id,
"path": artifact.path,
"headings": missing_headings,
}
)
def _check_required_top_level_files(
repo_root: Path,
errors: list[dict[str, Any]],