feat(ITC-WP-0016): establish PracticePattern language
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a025c2-407a-7a32-b40a-f37a52f03f62
This commit is contained in:
parent
5e2435aaf9
commit
149d2ced70
27 changed files with 1119 additions and 99 deletions
|
|
@ -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":
|
||||
|
|
|
|||
|
|
@ -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]],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue