generated from coulomb/repo-seed
939 lines
33 KiB
Python
939 lines
33 KiB
Python
from __future__ import annotations
|
|
|
|
from collections import defaultdict
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import yaml
|
|
|
|
|
|
GENERATED_NOTICE = "<!-- GENERATED by info_tech_canon; do not edit by hand. -->"
|
|
RETRIEVAL_ARTIFACT_KINDS = {
|
|
"access-descriptor-set",
|
|
"benefit-analysis",
|
|
"benchmark-findings",
|
|
"benchmark-workspace",
|
|
"capture-criteria",
|
|
"caring-mapping",
|
|
"comparison-frame",
|
|
"comparison-report",
|
|
"concept-catalog",
|
|
"conformance-pack",
|
|
"consumer-workplan-brief",
|
|
"evaluation-pack",
|
|
"evaluation-question-set",
|
|
"example",
|
|
"extension-candidate-set",
|
|
"interface-card-expectation",
|
|
"kernel",
|
|
"mapping",
|
|
"mapping-expectation",
|
|
"model",
|
|
"model-extension",
|
|
"native-concept-map",
|
|
"pattern",
|
|
"profile-alignment",
|
|
"profile",
|
|
"standard",
|
|
"visualization-example-set",
|
|
}
|
|
CONSUMER_BRIEF_IDS = ("user-engine", "railiance-fabric", "repo-scoping")
|
|
COMMON_DISTINCTIONS = [
|
|
{
|
|
"id": "actor-subject-principal",
|
|
"title": "Actor vs Subject vs Principal",
|
|
"summary": "Use actor for the acting entity in a context, subject for the entity a policy evaluates, and principal for the authenticated identity bound to access decisions.",
|
|
"source_artifacts": [
|
|
"model/organization",
|
|
"model/access-control",
|
|
"standard/caring",
|
|
],
|
|
},
|
|
{
|
|
"id": "organization-role-access-role-caring-role",
|
|
"title": "Organization Role vs AccessRole vs CARING role",
|
|
"summary": "Organization roles describe responsibility or position; access roles describe permissions; CARING roles classify access-governance needs and analysis.",
|
|
"source_artifacts": [
|
|
"model/organization",
|
|
"model/access-control",
|
|
"standard/caring",
|
|
],
|
|
},
|
|
{
|
|
"id": "policy-control-evidence",
|
|
"title": "Policy vs Control vs Evidence",
|
|
"summary": "Policy states intent or rule, control implements or enforces that rule, and evidence records why the claim should be trusted.",
|
|
"source_artifacts": [
|
|
"model/governance",
|
|
"model/security",
|
|
"model/observability",
|
|
],
|
|
},
|
|
{
|
|
"id": "intent-scope-purpose",
|
|
"title": "Intent vs Scope vs Purpose",
|
|
"summary": "Intent captures why a producer or consumer exists, scope bounds producer ownership and promises, and purpose captures consumer demand anchored in consumer intent.",
|
|
"source_artifacts": [
|
|
"kernel/itc-core",
|
|
"model/purpose-demand-extension",
|
|
"pattern/intent-scope-purposes",
|
|
"profile/small-saas",
|
|
],
|
|
},
|
|
]
|
|
|
|
|
|
def generate_indexes(context: Any) -> dict[str, Any]:
|
|
assets: list[dict[str, Any]] = []
|
|
ownership = concept_ownership(context)
|
|
import_matrix = relationship_matrix(context)
|
|
|
|
assets.append(
|
|
_write_yaml(
|
|
context.infospace_root / "indexes" / "concept-ownership.yaml",
|
|
ownership,
|
|
)
|
|
)
|
|
assets.append(
|
|
_write_yaml(
|
|
context.infospace_root / "indexes" / "import-matrix.yaml",
|
|
import_matrix,
|
|
)
|
|
)
|
|
assets.append(
|
|
_write_yaml(
|
|
context.infospace_root / "indexes" / "artifact-tree.yaml",
|
|
artifact_tree(context),
|
|
)
|
|
)
|
|
assets.extend(generate_views(context, ownership, import_matrix)["files"])
|
|
return _result("index", assets)
|
|
|
|
|
|
def generate_views(
|
|
context: Any,
|
|
ownership: dict[str, Any] | None = None,
|
|
import_matrix: dict[str, Any] | None = None,
|
|
) -> dict[str, Any]:
|
|
ownership = ownership or concept_ownership(context)
|
|
import_matrix = import_matrix or relationship_matrix(context)
|
|
files = [
|
|
_write_text(
|
|
context.infospace_root / "views" / "by-standard.md",
|
|
_render_by_standard(context),
|
|
),
|
|
_write_text(
|
|
context.infospace_root / "views" / "by-concept.md",
|
|
_render_by_concept(ownership),
|
|
),
|
|
_write_text(
|
|
context.infospace_root / "views" / "by-profile.md",
|
|
_render_by_profile(context),
|
|
),
|
|
_write_text(
|
|
context.infospace_root / "views" / "by-mapping-target.md",
|
|
_render_by_mapping_target(context),
|
|
),
|
|
_write_text(
|
|
context.infospace_root / "views" / "kernel-overview.md",
|
|
_render_kernel_overview(context),
|
|
),
|
|
_write_text(
|
|
context.infospace_root / "views" / "import-matrix.md",
|
|
_render_import_matrix(import_matrix),
|
|
),
|
|
]
|
|
return _result("views", files)
|
|
|
|
|
|
def generate_tree(context: Any) -> dict[str, Any]:
|
|
tree = artifact_tree(context)
|
|
files = [
|
|
_write_yaml(context.infospace_root / "indexes" / "artifact-tree.yaml", tree),
|
|
_write_text(
|
|
context.infospace_root / "views" / "repository-tree.md",
|
|
_render_repository_tree(tree),
|
|
),
|
|
]
|
|
return _result("tree", files)
|
|
|
|
|
|
def generate_agent_briefs(context: Any) -> dict[str, Any]:
|
|
retrieval = retrieval_index(context)
|
|
files = [
|
|
_write_text(
|
|
context.infospace_root / "agent" / "global-agent-brief.md",
|
|
_render_global_agent_brief(context, retrieval),
|
|
),
|
|
_write_text(
|
|
context.infospace_root / "agent" / "retrieval-index.md",
|
|
_render_retrieval_index_markdown(retrieval),
|
|
),
|
|
_write_yaml(
|
|
context.infospace_root / "agent" / "retrieval-index.yaml",
|
|
retrieval,
|
|
),
|
|
_write_json(
|
|
context.infospace_root / "agent" / "retrieval-index.json",
|
|
retrieval,
|
|
),
|
|
_write_yaml(
|
|
context.infospace_root / "agent" / "templates" / "canon-interface-card.template.yaml",
|
|
interface_card_template(),
|
|
),
|
|
_write_text(
|
|
context.infospace_root / "agent" / "templates" / "consumer-brief.template.md",
|
|
_render_consumer_brief_template(),
|
|
),
|
|
]
|
|
for artifact in sorted(context.infospace.artifacts, key=lambda item: item.id):
|
|
if artifact.kind in RETRIEVAL_ARTIFACT_KINDS:
|
|
files.append(
|
|
_write_text(
|
|
context.infospace_root / "agent" / "briefs" / f"{_safe_id(artifact.id)}.md",
|
|
_render_artifact_agent_brief(context, artifact, retrieval),
|
|
)
|
|
)
|
|
for consumer_id in CONSUMER_BRIEF_IDS:
|
|
files.append(
|
|
_write_text(
|
|
context.infospace_root / "agent" / "consumer-briefs" / f"{consumer_id}.md",
|
|
_render_consumer_brief(consumer_id),
|
|
)
|
|
)
|
|
return _result("agent-briefs", files)
|
|
|
|
|
|
def list_generated_views(context: Any) -> dict[str, Any]:
|
|
views = []
|
|
for path in sorted((context.infospace_root / "views").glob("*.md")):
|
|
views.append(
|
|
{
|
|
"name": path.name,
|
|
"path": str(path.relative_to(context.infospace_root)),
|
|
"generated": _is_generated(path),
|
|
}
|
|
)
|
|
return {"ok": True, "count": len(views), "views": views}
|
|
|
|
|
|
def read_generated_view(context: Any, name: str) -> dict[str, Any]:
|
|
if "/" in name or "\\" in name:
|
|
raise ValueError("View name must be a single file name.")
|
|
path = context.infospace_root / "views" / name
|
|
if not path.is_file():
|
|
raise FileNotFoundError(name)
|
|
return {
|
|
"ok": True,
|
|
"name": name,
|
|
"path": str(path.relative_to(context.infospace_root)),
|
|
"generated": _is_generated(path),
|
|
"content": path.read_text(encoding="utf-8"),
|
|
}
|
|
|
|
|
|
def concept_ownership(context: Any) -> dict[str, Any]:
|
|
concepts: list[dict[str, Any]] = []
|
|
for artifact in sorted(context.infospace.artifacts, key=lambda item: item.id):
|
|
concepts.append(
|
|
{
|
|
"concept": artifact.title,
|
|
"owner": artifact.id,
|
|
"path": artifact.path,
|
|
"source": "artifact_title",
|
|
}
|
|
)
|
|
frontmatter = _frontmatter(context.infospace_root / artifact.path)
|
|
owned = frontmatter.get("owned_concepts") or []
|
|
if isinstance(owned, list):
|
|
for concept in owned:
|
|
concepts.append(
|
|
{
|
|
"concept": str(concept),
|
|
"owner": artifact.id,
|
|
"path": artifact.path,
|
|
"source": "frontmatter.owned_concepts",
|
|
}
|
|
)
|
|
|
|
by_key: dict[str, list[dict[str, Any]]] = defaultdict(list)
|
|
for item in concepts:
|
|
by_key[_normalize_concept(item["concept"])].append(item)
|
|
|
|
duplicates = [
|
|
{"normalized": key, "candidates": items}
|
|
for key, items in sorted(by_key.items())
|
|
if len(items) > 1
|
|
]
|
|
conflicts = [
|
|
{
|
|
"normalized": item["normalized"],
|
|
"owners": sorted({candidate["owner"] for candidate in item["candidates"]}),
|
|
"candidates": item["candidates"],
|
|
}
|
|
for item in duplicates
|
|
if len({candidate["owner"] for candidate in item["candidates"]}) > 1
|
|
]
|
|
return {
|
|
"concept_count": len(concepts),
|
|
"concepts": concepts,
|
|
"duplicate_candidates": duplicates,
|
|
"ownership_conflicts": conflicts,
|
|
}
|
|
|
|
|
|
def relationship_matrix(context: Any) -> dict[str, Any]:
|
|
artifact_ids = sorted(artifact.id for artifact in context.infospace.artifacts)
|
|
rows: list[dict[str, Any]] = []
|
|
for artifact in sorted(context.infospace.artifacts, key=lambda item: item.id):
|
|
targets: dict[str, list[str]] = {target: [] for target in artifact_ids}
|
|
for relationship in artifact.relationships:
|
|
target = relationship.get("target")
|
|
relation_type = str(relationship.get("type") or "related")
|
|
if isinstance(target, str) and target in targets:
|
|
targets[target].append(relation_type)
|
|
rows.append(
|
|
{
|
|
"artifact": artifact.id,
|
|
"targets": {
|
|
target: sorted(types)
|
|
for target, types in targets.items()
|
|
if types
|
|
},
|
|
}
|
|
)
|
|
return {"artifacts": artifact_ids, "rows": rows}
|
|
|
|
|
|
def artifact_tree(context: Any) -> dict[str, Any]:
|
|
files: list[dict[str, Any]] = []
|
|
for path in sorted(context.infospace_root.rglob("*")):
|
|
if path.is_file():
|
|
relative = path.relative_to(context.infospace_root)
|
|
files.append(
|
|
{
|
|
"path": str(relative),
|
|
"directory": str(relative.parent),
|
|
"name": path.name,
|
|
}
|
|
)
|
|
return {"root": "infospace", "file_count": len(files), "files": files}
|
|
|
|
|
|
def retrieval_index(context: Any) -> dict[str, Any]:
|
|
ownership = concept_ownership(context)
|
|
concepts_by_owner: dict[str, list[str]] = defaultdict(list)
|
|
for concept in ownership["concepts"]:
|
|
concepts_by_owner[str(concept["owner"])].append(str(concept["concept"]))
|
|
|
|
items = []
|
|
for artifact in sorted(context.infospace.artifacts, key=lambda item: item.id):
|
|
relationships = [
|
|
{
|
|
"type": str(relationship.get("type") or "related"),
|
|
"target": str(relationship.get("target") or ""),
|
|
}
|
|
for relationship in artifact.relationships
|
|
]
|
|
imports = [
|
|
item["target"]
|
|
for item in relationships
|
|
if item["type"] in {"imports", "requires", "uses", "conforms_to"}
|
|
]
|
|
warnings = []
|
|
source_path = str(artifact.provenance.get("source_path") or artifact.path)
|
|
if not (context.repo_root / source_path).is_file() and not (
|
|
context.infospace_root / source_path
|
|
).is_file():
|
|
warnings.append(
|
|
{
|
|
"code": "source_path_not_file",
|
|
"source_path": source_path,
|
|
}
|
|
)
|
|
items.append(
|
|
{
|
|
"id": artifact.id,
|
|
"kind": artifact.kind,
|
|
"title": artifact.title,
|
|
"canonical_path": artifact.path,
|
|
"source_path": source_path,
|
|
"summary": _summary_for_artifact(artifact),
|
|
"owned_concepts": sorted(set(concepts_by_owner.get(artifact.id, []))),
|
|
"imports": sorted(set(imports)),
|
|
"relationships": relationships,
|
|
"warnings": warnings,
|
|
}
|
|
)
|
|
|
|
return {
|
|
"schema": "info-tech-canon.retrieval-index.v1",
|
|
"infospace": context.infospace.config.slug,
|
|
"item_count": len(items),
|
|
"items": items,
|
|
"common_distinctions": COMMON_DISTINCTIONS,
|
|
}
|
|
|
|
|
|
def _render_by_standard(context: Any) -> str:
|
|
lines = _heading("By Standard")
|
|
standards = [
|
|
artifact
|
|
for artifact in context.infospace.artifacts
|
|
if artifact.kind in {"kernel", "standard"}
|
|
]
|
|
for artifact in sorted(standards, key=lambda item: item.id):
|
|
lines.extend(
|
|
[
|
|
f"## {artifact.title}",
|
|
"",
|
|
f"- ID: `{artifact.id}`",
|
|
f"- Kind: `{artifact.kind}`",
|
|
f"- Path: `{artifact.path}`",
|
|
f"- Relationships: {len(artifact.relationships)}",
|
|
"",
|
|
]
|
|
)
|
|
return "\n".join(lines).rstrip() + "\n"
|
|
|
|
|
|
def _render_by_concept(ownership: dict[str, Any]) -> str:
|
|
lines = _heading("By Concept")
|
|
lines.extend(
|
|
[
|
|
f"Concept count: **{ownership['concept_count']}**",
|
|
"",
|
|
"| Concept | Owner | Source |",
|
|
"| --- | --- | --- |",
|
|
]
|
|
)
|
|
for concept in ownership["concepts"]:
|
|
lines.append(
|
|
f"| {concept['concept']} | `{concept['owner']}` | `{concept['source']}` |"
|
|
)
|
|
lines.extend(["", "## Duplicate Candidates", ""])
|
|
duplicates = ownership["duplicate_candidates"]
|
|
if not duplicates:
|
|
lines.append("No duplicate concept candidates detected.")
|
|
else:
|
|
for duplicate in duplicates:
|
|
lines.append(f"- `{duplicate['normalized']}`")
|
|
lines.extend(["", "## Ownership Conflicts", ""])
|
|
conflicts = ownership["ownership_conflicts"]
|
|
if not conflicts:
|
|
lines.append("No ownership conflicts detected.")
|
|
else:
|
|
for conflict in conflicts:
|
|
owners = ", ".join(f"`{owner}`" for owner in conflict["owners"])
|
|
lines.append(f"- `{conflict['normalized']}` owned by {owners}")
|
|
return "\n".join(lines).rstrip() + "\n"
|
|
|
|
|
|
def _render_by_profile(context: Any) -> str:
|
|
lines = _heading("By Profile")
|
|
profiles = sorted((context.infospace_root / "profiles").glob("*/profile.yaml"))
|
|
if not profiles:
|
|
lines.append("No profiles have been registered yet.")
|
|
for path in profiles:
|
|
lines.extend(
|
|
[
|
|
f"## {path.parent.name}",
|
|
"",
|
|
f"- Path: `{path.relative_to(context.infospace_root)}`",
|
|
"",
|
|
]
|
|
)
|
|
return "\n".join(lines).rstrip() + "\n"
|
|
|
|
|
|
def _render_by_mapping_target(context: Any) -> str:
|
|
incoming: dict[str, list[tuple[str, str]]] = defaultdict(list)
|
|
for artifact in context.infospace.artifacts:
|
|
for relationship in artifact.relationships:
|
|
target = relationship.get("target")
|
|
relation_type = str(relationship.get("type") or "related")
|
|
if isinstance(target, str):
|
|
incoming[target].append((artifact.id, relation_type))
|
|
lines = _heading("By Mapping Target")
|
|
for target in sorted(incoming):
|
|
lines.extend([f"## `{target}`", ""])
|
|
for source, relation_type in sorted(incoming[target]):
|
|
lines.append(f"- `{source}` via `{relation_type}`")
|
|
lines.append("")
|
|
return "\n".join(lines).rstrip() + "\n"
|
|
|
|
|
|
def _render_kernel_overview(context: Any) -> str:
|
|
kind_counts: dict[str, int] = defaultdict(int)
|
|
relationship_counts: dict[str, int] = defaultdict(int)
|
|
for artifact in context.infospace.artifacts:
|
|
kind_counts[artifact.kind] += 1
|
|
for relationship in artifact.relationships:
|
|
relationship_counts[str(relationship.get("type") or "related")] += 1
|
|
lines = _heading("Kernel Overview")
|
|
lines.extend(
|
|
[
|
|
f"- Infospace: `{context.infospace.config.slug}`",
|
|
f"- Artifacts: {len(context.infospace.artifacts)}",
|
|
"",
|
|
"## Artifact Kinds",
|
|
"",
|
|
]
|
|
)
|
|
for kind, count in sorted(kind_counts.items()):
|
|
lines.append(f"- `{kind}`: {count}")
|
|
lines.extend(["", "## Relationship Types", ""])
|
|
for relation_type, count in sorted(relationship_counts.items()):
|
|
lines.append(f"- `{relation_type}`: {count}")
|
|
return "\n".join(lines).rstrip() + "\n"
|
|
|
|
|
|
def _render_import_matrix(matrix: dict[str, Any]) -> str:
|
|
artifacts = matrix["artifacts"]
|
|
lines = _heading("Import Matrix")
|
|
header = "| Artifact | " + " | ".join(f"`{artifact}`" for artifact in artifacts) + " |"
|
|
divider = "| --- | " + " | ".join("---" for _ in artifacts) + " |"
|
|
lines.extend([header, divider])
|
|
for row in matrix["rows"]:
|
|
cells = []
|
|
targets = row["targets"]
|
|
for artifact in artifacts:
|
|
cells.append(", ".join(f"`{item}`" for item in targets.get(artifact, [])))
|
|
lines.append(f"| `{row['artifact']}` | " + " | ".join(cells) + " |")
|
|
return "\n".join(lines).rstrip() + "\n"
|
|
|
|
|
|
def _render_repository_tree(tree: dict[str, Any]) -> str:
|
|
lines = _heading("Repository Tree")
|
|
lines.append(f"File count: **{tree['file_count']}**")
|
|
lines.append("")
|
|
for file_info in tree["files"]:
|
|
lines.append(f"- `{file_info['path']}`")
|
|
return "\n".join(lines).rstrip() + "\n"
|
|
|
|
|
|
def _render_global_agent_brief(context: Any, retrieval: dict[str, Any]) -> str:
|
|
lines = _heading("Global Agent Brief")
|
|
lines.extend(
|
|
[
|
|
"This brief summarizes the current canon service surface for agents.",
|
|
"",
|
|
f"- Infospace slug: `{context.infospace.config.slug}`",
|
|
f"- Artifact count: {len(context.infospace.artifacts)}",
|
|
f"- Retrieval index items: {retrieval['item_count']}",
|
|
"- Primary confidence command: `make validate`",
|
|
"- Refresh generated indexes and views with: `make index`",
|
|
"- Refresh agent briefs and interface templates with: `make agent-briefs`",
|
|
"",
|
|
"## Useful Commands",
|
|
"",
|
|
"- `PYTHONPATH=src python3 -m info_tech_canon inspect`",
|
|
"- `PYTHONPATH=src python3 -m info_tech_canon validate`",
|
|
"- `PYTHONPATH=src python3 -m info_tech_canon graph`",
|
|
"- `PYTHONPATH=src python3 -m info_tech_canon index`",
|
|
"- `PYTHONPATH=src python3 -m info_tech_canon profile validate small-saas`",
|
|
"",
|
|
"## Retrieval Entry Points",
|
|
"",
|
|
"- `agent/retrieval-index.md`",
|
|
"- `agent/retrieval-index.yaml`",
|
|
"- `agent/retrieval-index.json`",
|
|
"- `agent/briefs/` for per-artifact briefs",
|
|
"- `agent/templates/canon-interface-card.template.yaml`",
|
|
"",
|
|
"## Common Distinctions",
|
|
"",
|
|
]
|
|
)
|
|
for distinction in retrieval["common_distinctions"]:
|
|
lines.append(f"- **{distinction['title']}**: {distinction['summary']}")
|
|
lines.extend(
|
|
[
|
|
"",
|
|
"## Consumption Notes",
|
|
"",
|
|
"- Treat `seeds/` as provenance.",
|
|
"- Treat `infospace/` as the service-consumable canon root.",
|
|
"- Generated files are marked and can be refreshed deterministically.",
|
|
]
|
|
)
|
|
return "\n".join(lines).rstrip() + "\n"
|
|
|
|
|
|
def _render_retrieval_index_markdown(retrieval: dict[str, Any]) -> str:
|
|
lines = _heading("Retrieval Index")
|
|
lines.extend(
|
|
[
|
|
f"Schema: `{retrieval['schema']}`",
|
|
f"Infospace: `{retrieval['infospace']}`",
|
|
f"Items: **{retrieval['item_count']}**",
|
|
"",
|
|
"## Common Distinctions",
|
|
"",
|
|
]
|
|
)
|
|
for distinction in retrieval["common_distinctions"]:
|
|
sources = ", ".join(f"`{item}`" for item in distinction["source_artifacts"])
|
|
lines.append(f"- **{distinction['title']}**: {distinction['summary']} Sources: {sources}")
|
|
lines.extend(["", "## Items", ""])
|
|
for item in retrieval["items"]:
|
|
imports = ", ".join(f"`{target}`" for target in item["imports"]) or "none"
|
|
concepts = ", ".join(f"`{concept}`" for concept in item["owned_concepts"]) or "none"
|
|
lines.extend(
|
|
[
|
|
f"### {item['title']}",
|
|
"",
|
|
f"- ID: `{item['id']}`",
|
|
f"- Kind: `{item['kind']}`",
|
|
f"- Canonical path: `{item['canonical_path']}`",
|
|
f"- Source path: `{item['source_path']}`",
|
|
f"- Summary: {item['summary']}",
|
|
f"- Imports and anchors: {imports}",
|
|
f"- Owned concepts: {concepts}",
|
|
"",
|
|
]
|
|
)
|
|
return "\n".join(lines).rstrip() + "\n"
|
|
|
|
|
|
def _render_artifact_agent_brief(
|
|
context: Any,
|
|
artifact: Any,
|
|
retrieval: dict[str, Any],
|
|
) -> str:
|
|
item = next(entry for entry in retrieval["items"] if entry["id"] == artifact.id)
|
|
frontmatter = {
|
|
"id": f"agent-brief/{_safe_id(artifact.id)}",
|
|
"artifact_id": artifact.id,
|
|
"source_path": artifact.path,
|
|
"source_kind": artifact.kind,
|
|
"generated": True,
|
|
}
|
|
lines = [
|
|
"---",
|
|
yaml.safe_dump(frontmatter, sort_keys=False).strip(),
|
|
"---",
|
|
"",
|
|
GENERATED_NOTICE,
|
|
"",
|
|
f"# Agent Brief: {artifact.title}",
|
|
"",
|
|
f"- Artifact ID: `{artifact.id}`",
|
|
f"- Kind: `{artifact.kind}`",
|
|
f"- Canonical path: `{artifact.path}`",
|
|
f"- Full source: `{artifact.path}`",
|
|
f"- Summary: {item['summary']}",
|
|
"",
|
|
"## Retrieval Hints",
|
|
"",
|
|
]
|
|
if item["imports"]:
|
|
lines.append("Imports and anchors:")
|
|
lines.extend(f"- `{target}`" for target in item["imports"])
|
|
else:
|
|
lines.append("No imports or anchors recorded.")
|
|
lines.extend(["", "## Owned Concepts", ""])
|
|
if item["owned_concepts"]:
|
|
lines.extend(f"- `{concept}`" for concept in item["owned_concepts"])
|
|
else:
|
|
lines.append("No owned concepts recorded yet.")
|
|
lines.extend(["", "## Related Distinctions", ""])
|
|
related = [
|
|
distinction
|
|
for distinction in retrieval["common_distinctions"]
|
|
if artifact.id in distinction["source_artifacts"]
|
|
]
|
|
if related:
|
|
for distinction in related:
|
|
lines.append(f"- **{distinction['title']}**: {distinction['summary']}")
|
|
else:
|
|
lines.append("No common distinction is anchored directly on this artifact.")
|
|
return "\n".join(lines).rstrip() + "\n"
|
|
|
|
|
|
def interface_card_template() -> dict[str, Any]:
|
|
return {
|
|
"schema": "info-tech-canon.interface-card.v1",
|
|
"id": "consumer-repo/interface-card",
|
|
"title": "Consumer Repo Canon Interface Card",
|
|
"consumer": {
|
|
"repo": "",
|
|
"domain": "",
|
|
"owner": "",
|
|
"intent": "",
|
|
"scope": "",
|
|
"purposes": [
|
|
{
|
|
"id": "",
|
|
"use_case": "",
|
|
"consumer_need": "",
|
|
"demand_signals": [],
|
|
}
|
|
],
|
|
},
|
|
"canon_surfaces": {
|
|
"implemented_profiles": [],
|
|
"consumed_artifacts": [],
|
|
"owned_concepts": [],
|
|
"produced_concepts": [],
|
|
"consumed_concepts": [],
|
|
"mappings": [],
|
|
},
|
|
"validation_expectations": {
|
|
"commands": [],
|
|
"evidence_required": [],
|
|
"known_gaps": [],
|
|
},
|
|
"purpose_fit": {
|
|
"state": "",
|
|
"matched_capabilities": [],
|
|
"scope_pressure": "",
|
|
"recommended_disposition": "",
|
|
},
|
|
"consumer_needs": {
|
|
"current": [],
|
|
"requested_extensions": [],
|
|
"feedback": [],
|
|
},
|
|
}
|
|
|
|
|
|
def _render_consumer_brief_template() -> str:
|
|
lines = [
|
|
"---",
|
|
"id: consumer-brief/template",
|
|
"consumer: TBD",
|
|
"generated: true",
|
|
"---",
|
|
"",
|
|
GENERATED_NOTICE,
|
|
"",
|
|
"# Consumer Brief Template",
|
|
"",
|
|
"## Consumer Intent",
|
|
"",
|
|
"- Intent:",
|
|
"- Scope:",
|
|
"- Purposes:",
|
|
"- Use cases:",
|
|
"- Demand signals:",
|
|
"",
|
|
"## Canon Surfaces",
|
|
"",
|
|
"- Implemented profiles:",
|
|
"- Consumed standards:",
|
|
"- Produced concepts:",
|
|
"- Consumed concepts:",
|
|
"",
|
|
"## Validation Expectations",
|
|
"",
|
|
"- Commands:",
|
|
"- Evidence:",
|
|
"- Known gaps:",
|
|
"",
|
|
"## Purpose Fit",
|
|
"",
|
|
"- State:",
|
|
"- Matched producer capabilities:",
|
|
"- Scope pressure:",
|
|
"- Requested evolution:",
|
|
]
|
|
return "\n".join(lines).rstrip() + "\n"
|
|
|
|
|
|
def _render_consumer_brief(consumer_id: str) -> str:
|
|
titles = {
|
|
"user-engine": "User Engine Canon Consumer Brief",
|
|
"railiance-fabric": "Railiance Fabric Canon Consumer Brief",
|
|
"repo-scoping": "Repo Scoping Canon Consumer Brief",
|
|
}
|
|
purposes = {
|
|
"user-engine": "Evaluate user-management concepts, roles, access traces, profile claims, and governance evidence against the canon before integration.",
|
|
"railiance-fabric": "Use the canon to make captured entities and edges cleaner for conformance and visualization.",
|
|
"repo-scoping": "Compare repo-scoping concepts with canon INTENT, SCOPE, PURPOSES, and interface-card expectations.",
|
|
}
|
|
starting_points = {
|
|
"user-engine": [
|
|
"evaluations/user-engine/evaluation-pack.yaml",
|
|
"evaluations/user-engine/questions.yaml",
|
|
"evaluations/user-engine/interface-card-expectations.yaml",
|
|
"evaluations/user-engine/small-saas-alignment.yaml",
|
|
"profiles/small-saas/profile.yaml",
|
|
],
|
|
"railiance-fabric": [
|
|
"evaluations/railiance-fabric/conformance-pack.yaml",
|
|
"evaluations/railiance-fabric/entity-edge-capture-criteria.yaml",
|
|
"evaluations/railiance-fabric/mapping-expectations.yaml",
|
|
"evaluations/railiance-fabric/visualization-examples.yaml",
|
|
"models/landscape/InfoTechCanonLandscapeModel.md",
|
|
"models/network/InfoTechCanonNetworkModel.md",
|
|
],
|
|
"repo-scoping": [
|
|
"evaluations/repo-scoping/comparison-report.md",
|
|
"evaluations/repo-scoping/comparison-frame.yaml",
|
|
"evaluations/repo-scoping/canon-benefit-analysis.yaml",
|
|
"evaluations/repo-scoping/extension-candidates.yaml",
|
|
"models/governance/InfoTechCanonPurposeDemandExtension.md",
|
|
"patterns/intent-scope-purposes.md",
|
|
"agent/templates/canon-interface-card.template.yaml",
|
|
"examples/consumer-purpose-portfolio.yaml",
|
|
],
|
|
}
|
|
lines = [
|
|
"---",
|
|
f"id: consumer-brief/{consumer_id}",
|
|
f"consumer: {consumer_id}",
|
|
"generated: true",
|
|
"---",
|
|
"",
|
|
GENERATED_NOTICE,
|
|
"",
|
|
f"# {titles[consumer_id]}",
|
|
"",
|
|
"## Purpose",
|
|
"",
|
|
purposes[consumer_id],
|
|
"",
|
|
"## Starting Points",
|
|
"",
|
|
"- `agent/retrieval-index.md`",
|
|
"- `agent/templates/canon-interface-card.template.yaml`",
|
|
"- `models/governance/InfoTechCanonPurposeDemandExtension.md`",
|
|
"- `patterns/intent-scope-purposes.md`",
|
|
"- `examples/consumer-purpose-portfolio.yaml`",
|
|
"- `views/by-concept.md`",
|
|
]
|
|
for path in starting_points[consumer_id]:
|
|
lines.append(f"- `{path}`")
|
|
lines.extend(
|
|
[
|
|
"",
|
|
"## Workplan Boundary",
|
|
"",
|
|
"Adoption and repo-specific implementation workplans belong in the consumer repository.",
|
|
]
|
|
)
|
|
return "\n".join(lines).rstrip() + "\n"
|
|
|
|
|
|
def _heading(title: str) -> list[str]:
|
|
return [GENERATED_NOTICE, "", f"# {title}", ""]
|
|
|
|
|
|
def _write_text(path: Path, content: str) -> dict[str, Any]:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
old = path.read_text(encoding="utf-8") if path.exists() else None
|
|
changed = old != content
|
|
if changed:
|
|
path.write_text(content, encoding="utf-8")
|
|
return {"path": str(path), "changed": changed}
|
|
|
|
|
|
def _write_yaml(path: Path, data: dict[str, Any]) -> dict[str, Any]:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
content = yaml.safe_dump(data, sort_keys=False)
|
|
return _write_text(path, content)
|
|
|
|
|
|
def _write_json(path: Path, data: dict[str, Any]) -> dict[str, Any]:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
content = json.dumps(data, indent=2, sort_keys=True) + "\n"
|
|
return _write_text(path, content)
|
|
|
|
|
|
def _result(kind: str, files: list[dict[str, Any]]) -> dict[str, Any]:
|
|
return {
|
|
"ok": True,
|
|
"kind": kind,
|
|
"count": len(files),
|
|
"changed": [item for item in files if item["changed"]],
|
|
"files": files,
|
|
}
|
|
|
|
|
|
def _frontmatter(path: Path) -> dict[str, Any]:
|
|
text = path.read_text(encoding="utf-8")
|
|
if not text.startswith("---\n"):
|
|
return {}
|
|
end = text.find("\n---\n", 4)
|
|
if end == -1:
|
|
return {}
|
|
data = yaml.safe_load(text[4:end]) or {}
|
|
return data if isinstance(data, dict) else {}
|
|
|
|
|
|
def _normalize_concept(value: str) -> str:
|
|
return "-".join(value.lower().replace("_", "-").split())
|
|
|
|
|
|
def _safe_id(value: str) -> str:
|
|
return value.replace("/", "-").replace("_", "-")
|
|
|
|
|
|
def _summary_for_artifact(artifact: Any) -> str:
|
|
if artifact.kind == "profile-artifact":
|
|
return f"Example artifact for the {artifact.provenance.get('profile', 'unknown')} profile: {artifact.title}."
|
|
if artifact.kind == "access-descriptor-set":
|
|
return f"Structured CARING access descriptor set: {artifact.title}."
|
|
if artifact.kind == "benefit-analysis":
|
|
return f"Consumer benefit analysis against canon surfaces: {artifact.title}."
|
|
if artifact.kind == "benchmark-findings":
|
|
return f"Benchmark findings, gaps, and canon pressure: {artifact.title}."
|
|
if artifact.kind == "benchmark-workspace":
|
|
return f"Benchmark workspace definition and review criteria: {artifact.title}."
|
|
if artifact.kind == "capture-criteria":
|
|
return f"Criteria for canonical entity and edge capture: {artifact.title}."
|
|
if artifact.kind == "caring-mapping":
|
|
return f"Native access model to CARING mapping: {artifact.title}."
|
|
if artifact.kind == "comparison-frame":
|
|
return f"Structured comparison questions and domains: {artifact.title}."
|
|
if artifact.kind == "comparison-report":
|
|
return f"Canon-side comparison report: {artifact.title}."
|
|
if artifact.kind == "concept-catalog":
|
|
return f"Structured candidate concept catalog: {artifact.title}."
|
|
if artifact.kind == "conformance-pack":
|
|
return f"Machine-readable canon-side conformance support pack: {artifact.title}."
|
|
if artifact.kind == "consumer-workplan-brief":
|
|
return f"Consumer repo workplan seed brief: {artifact.title}."
|
|
if artifact.kind == "evaluation-pack":
|
|
return f"Machine-readable canon-side evaluation pack: {artifact.title}."
|
|
if artifact.kind == "evaluation-question-set":
|
|
return f"Structured canon evaluation question set: {artifact.title}."
|
|
if artifact.kind == "example":
|
|
return f"Canon-side example artifact: {artifact.title}."
|
|
if artifact.kind == "extension-candidate-set":
|
|
return f"Reviewable canon extension candidate set: {artifact.title}."
|
|
if artifact.kind == "interface-card-expectation":
|
|
return f"Expected Canon Interface Card fields and mappings: {artifact.title}."
|
|
if artifact.kind == "mapping":
|
|
return f"Mapping artifact connecting canon surfaces: {artifact.title}."
|
|
if artifact.kind == "mapping-expectation":
|
|
return f"Expected mappings between consumer graph capture and canon surfaces: {artifact.title}."
|
|
if artifact.kind == "model-extension":
|
|
return f"Candidate extension to an existing canon model: {artifact.title}."
|
|
if artifact.kind == "native-concept-map":
|
|
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 == "profile-alignment":
|
|
return f"Profile-specific evaluation alignment artifact: {artifact.title}."
|
|
if artifact.kind == "visualization-example-set":
|
|
return f"Graph visualization examples and bad-shape corrections: {artifact.title}."
|
|
if artifact.kind == "profile":
|
|
return f"Profile that constrains canon artifacts for a practical implementation slice: {artifact.title}."
|
|
if artifact.kind == "kernel":
|
|
return f"Kernel artifact that defines canon structure or integration: {artifact.title}."
|
|
if artifact.kind == "model":
|
|
return f"Domain model used by canon profiles and standards: {artifact.title}."
|
|
if artifact.kind == "standard":
|
|
return f"Cross-cutting canon standard: {artifact.title}."
|
|
return f"Canon artifact: {artifact.title}."
|
|
|
|
|
|
def _is_generated(path: Path) -> bool:
|
|
try:
|
|
return path.read_text(encoding="utf-8").startswith(GENERATED_NOTICE)
|
|
except FileNotFoundError:
|
|
return False
|